From c737b42a4308078377fa3b14499a8dcfed2be19c Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Thu, 19 Jul 2018 17:13:28 -0700 Subject: [PATCH] Removed picoTCP source from project --- ext/picotcp/.gitignore | 24 - ext/picotcp/.travis.yml | 13 - ext/picotcp/CONTRIBUTING.md | 8 - ext/picotcp/COPYING | 8 - ext/picotcp/LICENSE.GPLv2 | 339 -- ext/picotcp/LICENSE.GPLv3 | 674 --- ext/picotcp/MODTREE | 27 - ext/picotcp/Makefile | 508 -- ext/picotcp/Makefile.watcom | 403 -- ext/picotcp/README.md | 220 - ext/picotcp/RFC/get_all_rfc | 15 - ext/picotcp/RFC/rfc0813.txt | 1167 ---- ext/picotcp/RFC/rfc0814.txt | 763 --- ext/picotcp/RFC/rfc0816.txt | 648 --- ext/picotcp/RFC/rfc0817.txt | 1388 ----- ext/picotcp/RFC/rfc0826.txt | 470 -- ext/picotcp/RFC/rfc0872.txt | 549 -- ext/picotcp/RFC/rfc0879.txt | 638 --- ext/picotcp/RFC/rfc0896.txt | 512 -- ext/picotcp/RFC/rfc0964.txt | 570 -- ext/picotcp/RFC/rfc1071.txt | 1417 ----- ext/picotcp/RFC/rfc1072.txt | 893 --- ext/picotcp/RFC/rfc1106.txt | 731 --- ext/picotcp/RFC/rfc1110.txt | 171 - ext/picotcp/RFC/rfc1146.txt | 283 - ext/picotcp/RFC/rfc1156.txt | 5099 ----------------- ext/picotcp/RFC/rfc1180.txt | 1571 ----- ext/picotcp/RFC/rfc1185.txt | 1179 ---- ext/picotcp/RFC/rfc1213.txt | 3923 ------------- ext/picotcp/RFC/rfc1263.txt | 1067 ---- ext/picotcp/RFC/rfc1332.txt | 787 --- ext/picotcp/RFC/rfc1334.txt | 899 --- ext/picotcp/RFC/rfc1337.txt | 619 -- ext/picotcp/RFC/rfc1350.txt | 619 -- ext/picotcp/RFC/rfc1624.txt | 339 -- ext/picotcp/RFC/rfc1662.txt | 1440 ----- ext/picotcp/RFC/rfc1877.txt | 339 -- ext/picotcp/RFC/rfc1936.txt | 1179 ---- ext/picotcp/RFC/rfc1948.txt | 339 -- ext/picotcp/RFC/rfc1994.txt | 732 --- ext/picotcp/RFC/rfc2012.txt | 563 -- ext/picotcp/RFC/rfc2018.txt | 675 --- ext/picotcp/RFC/rfc2132.txt | 1907 ------ ext/picotcp/RFC/rfc2140.txt | 619 -- ext/picotcp/RFC/rfc2347.txt | 395 -- ext/picotcp/RFC/rfc2349.txt | 283 - ext/picotcp/RFC/rfc2385.txt | 339 -- ext/picotcp/RFC/rfc2398.txt | 843 --- ext/picotcp/RFC/rfc2415.txt | 619 -- ext/picotcp/RFC/rfc2416.txt | 395 -- ext/picotcp/RFC/rfc2452.txt | 563 -- ext/picotcp/RFC/rfc2474.txt | 1123 ---- ext/picotcp/RFC/rfc2488.txt | 1067 ---- ext/picotcp/RFC/rfc2581.txt | 787 --- ext/picotcp/RFC/rfc2675.txt | 507 -- ext/picotcp/RFC/rfc2861.txt | 619 -- ext/picotcp/RFC/rfc2873.txt | 451 -- ext/picotcp/RFC/rfc2883.txt | 955 --- ext/picotcp/RFC/rfc2884.txt | 1011 ---- ext/picotcp/RFC/rfc2914.txt | 955 --- ext/picotcp/RFC/rfc2923.txt | 843 --- ext/picotcp/RFC/rfc2988.txt | 451 -- ext/picotcp/RFC/rfc3042.txt | 507 -- ext/picotcp/RFC/rfc3124.txt | 1235 ---- ext/picotcp/RFC/rfc3150.txt | 955 --- ext/picotcp/RFC/rfc3155.txt | 899 --- ext/picotcp/RFC/rfc3360.txt | 1067 ---- ext/picotcp/RFC/rfc3366.txt | 1515 ----- ext/picotcp/RFC/rfc3390.txt | 843 --- ext/picotcp/RFC/rfc3465.txt | 563 -- ext/picotcp/RFC/rfc3481.txt | 1459 ----- ext/picotcp/RFC/rfc3517.txt | 731 --- ext/picotcp/RFC/rfc3522.txt | 787 --- ext/picotcp/RFC/rfc3540.txt | 731 --- ext/picotcp/RFC/rfc3562.txt | 395 -- ext/picotcp/RFC/rfc3708.txt | 507 -- ext/picotcp/RFC/rfc3742.txt | 395 -- ext/picotcp/RFC/rfc3782.txt | 1067 ---- ext/picotcp/RFC/rfc4015.txt | 731 --- ext/picotcp/RFC/rfc4022.txt | 1347 ----- ext/picotcp/RFC/rfc4138.txt | 1291 ----- ext/picotcp/RFC/rfc4278.txt | 395 -- ext/picotcp/docs/user_manual/README.md | 20 - ext/picotcp/docs/user_manual/build.sh | 3 - .../docs/user_manual/chap_api_aodv.tex | 42 - .../docs/user_manual/chap_api_dhcp_c.tex | 170 - .../docs/user_manual/chap_api_dhcp_d.tex | 71 - .../docs/user_manual/chap_api_dns_c.tex | 115 - .../docs/user_manual/chap_api_dns_sd.tex | 85 - .../docs/user_manual/chap_api_igmp.tex | 42 - .../docs/user_manual/chap_api_ipfilter.tex | 89 - .../docs/user_manual/chap_api_ipv4.tex | 561 -- .../docs/user_manual/chap_api_ipv6.tex | 533 -- .../docs/user_manual/chap_api_mdns.tex | 235 - ext/picotcp/docs/user_manual/chap_api_mld.tex | 42 - .../docs/user_manual/chap_api_olsr.tex | 49 - ext/picotcp/docs/user_manual/chap_api_ppp.tex | 257 - .../docs/user_manual/chap_api_slaacv4.tex | 44 - .../docs/user_manual/chap_api_sntp_c.tex | 96 - .../docs/user_manual/chap_api_sock.tex | 800 --- .../docs/user_manual/chap_api_tftp.tex | 911 --- ext/picotcp/docs/user_manual/chap_license.tex | 11 - .../docs/user_manual/chap_overview.tex | 68 - ext/picotcp/docs/user_manual/chap_rfcs.tex | 187 - ext/picotcp/docs/user_manual/layout.tex | 71 - ext/picotcp/docs/user_manual/layout1.tex | 27 - ext/picotcp/docs/user_manual/template_api.tex | 38 - ext/picotcp/docs/user_manual/user_doc.tex | 113 - .../docs/wiki_images/Protocol input.dia | Bin 1873 -> 0 bytes .../docs/wiki_images/Protocol output.dia | Bin 2584 -> 0 bytes .../docs/wiki_images/Protocol_input.png | Bin 25462 -> 0 bytes .../docs/wiki_images/Protocol_output.png | Bin 40420 -> 0 bytes .../docs/wiki_images/driver_stack_memory.dia | Bin 1788 -> 0 bytes .../docs/wiki_images/driver_stack_memory.png | Bin 14782 -> 0 bytes ext/picotcp/docs/wiki_images/petri_net.gif | Bin 37925 -> 0 bytes ext/picotcp/docs/wiki_images/picoTCP_logo.png | Bin 65949 -> 0 bytes ext/picotcp/docs/wiki_images/pico_frame.png | Bin 24976 -> 0 bytes ext/picotcp/docs/wiki_images/port_to_os.dia | Bin 1057 -> 0 bytes ext/picotcp/docs/wiki_images/port_to_os.png | Bin 7080 -> 0 bytes ext/picotcp/include/arch/pico_arm9.h | 35 - ext/picotcp/include/arch/pico_atsamd21j18.h | 61 - ext/picotcp/include/arch/pico_avr.h | 39 - ext/picotcp/include/arch/pico_cortex_m.h | 12 - ext/picotcp/include/arch/pico_dos.h | 44 - ext/picotcp/include/arch/pico_esp8266.h | 58 - ext/picotcp/include/arch/pico_generic_gcc.h | 117 - 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_pic32.h | 54 - ext/picotcp/include/arch/pico_posix.h | 137 - ext/picotcp/include/heap.h | 107 - ext/picotcp/include/pico_addressing.h | 127 - ext/picotcp/include/pico_config.h | 243 - ext/picotcp/include/pico_constants.h | 58 - ext/picotcp/include/pico_device.h | 56 - ext/picotcp/include/pico_eth.h | 21 - ext/picotcp/include/pico_frame.h | 131 - 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 | 271 - ext/picotcp/include/pico_socket_multicast.h | 10 - ext/picotcp/include/pico_stack.h | 111 - ext/picotcp/include/pico_tree.h | 93 - ext/picotcp/mkdeps.sh | 22 - ext/picotcp/modcheck.py | 92 - ext/picotcp/modules/pico_6lowpan.c | 1647 ------ ext/picotcp/modules/pico_6lowpan.h | 40 - ext/picotcp/modules/pico_6lowpan_ll.c | 454 -- ext/picotcp/modules/pico_6lowpan_ll.h | 122 - ext/picotcp/modules/pico_802154.c | 456 -- ext/picotcp/modules/pico_802154.h | 40 - ext/picotcp/modules/pico_aodv.c | 696 --- ext/picotcp/modules/pico_aodv.h | 130 - ext/picotcp/modules/pico_arp.c | 566 -- ext/picotcp/modules/pico_arp.h | 35 - ext/picotcp/modules/pico_dev_ipc.c | 109 - ext/picotcp/modules/pico_dev_ipc.h | 15 - ext/picotcp/modules/pico_dev_loop.c | 66 - ext/picotcp/modules/pico_dev_loop.h | 15 - ext/picotcp/modules/pico_dev_mock.c | 316 - 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 | 2312 -------- ext/picotcp/modules/pico_dev_ppp.h | 26 - ext/picotcp/modules/pico_dev_radio_mgr.c | 357 -- ext/picotcp/modules/pico_dev_radio_mgr.h | 14 - ext/picotcp/modules/pico_dev_radiotest.c | 486 -- ext/picotcp/modules/pico_dev_radiotest.h | 16 - ext/picotcp/modules/pico_dev_tap.c | 230 - ext/picotcp/modules/pico_dev_tap.h | 15 - ext/picotcp/modules/pico_dev_tap_windows.c | 1101 ---- 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 | 122 - ext/picotcp/modules/pico_dev_vde.h | 18 - ext/picotcp/modules/pico_dhcp_client.c | 1074 ---- 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 | 426 -- ext/picotcp/modules/pico_dhcp_server.h | 34 - ext/picotcp/modules/pico_dns_client.c | 846 --- ext/picotcp/modules/pico_dns_client.h | 58 - ext/picotcp/modules/pico_dns_common.c | 1784 ------ ext/picotcp/modules/pico_dns_common.h | 528 -- ext/picotcp/modules/pico_dns_sd.c | 568 -- ext/picotcp/modules/pico_dns_sd.h | 91 - ext/picotcp/modules/pico_ethernet.c | 447 -- ext/picotcp/modules/pico_ethernet.h | 18 - ext/picotcp/modules/pico_fragments.c | 573 -- ext/picotcp/modules/pico_fragments.h | 11 - ext/picotcp/modules/pico_hotplug_detection.c | 207 - ext/picotcp/modules/pico_hotplug_detection.h | 23 - ext/picotcp/modules/pico_icmp4.c | 434 -- ext/picotcp/modules/pico_icmp4.h | 162 - ext/picotcp/modules/pico_icmp6.c | 901 --- ext/picotcp/modules/pico_icmp6.h | 326 -- ext/picotcp/modules/pico_igmp.c | 1170 ---- ext/picotcp/modules/pico_igmp.h | 26 - ext/picotcp/modules/pico_ipfilter.c | 464 -- ext/picotcp/modules/pico_ipfilter.h | 29 - ext/picotcp/modules/pico_ipv4.c | 1660 ------ ext/picotcp/modules/pico_ipv4.h | 122 - ext/picotcp/modules/pico_ipv6.c | 2141 ------- ext/picotcp/modules/pico_ipv6.h | 189 - ext/picotcp/modules/pico_ipv6_nd.c | 1586 ----- ext/picotcp/modules/pico_ipv6_nd.h | 36 - ext/picotcp/modules/pico_mcast.c | 259 - ext/picotcp/modules/pico_mcast.h | 53 - ext/picotcp/modules/pico_mdns.c | 3687 ------------ ext/picotcp/modules/pico_mdns.h | 206 - ext/picotcp/modules/pico_mld.c | 1165 ---- ext/picotcp/modules/pico_mld.h | 119 - ext/picotcp/modules/pico_mm.c | 1615 ------ ext/picotcp/modules/pico_mm.h | 98 - ext/picotcp/modules/pico_nat.c | 589 -- ext/picotcp/modules/pico_nat.h | 90 - ext/picotcp/modules/pico_olsr.c | 1167 ---- ext/picotcp/modules/pico_olsr.h | 32 - ext/picotcp/modules/pico_posix.c | 99 - ext/picotcp/modules/pico_slaacv4.c | 307 - ext/picotcp/modules/pico_slaacv4.h | 18 - ext/picotcp/modules/pico_sntp_client.c | 552 -- ext/picotcp/modules/pico_sntp_client.h | 23 - ext/picotcp/modules/pico_socket_tcp.c | 272 - ext/picotcp/modules/pico_socket_tcp.h | 33 - ext/picotcp/modules/pico_socket_udp.c | 260 - 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 | 3307 ----------- ext/picotcp/modules/pico_tcp.h | 106 - ext/picotcp/modules/pico_tftp.c | 1323 ----- ext/picotcp/modules/pico_tftp.h | 83 - ext/picotcp/modules/pico_udp.c | 222 - ext/picotcp/modules/pico_udp.h | 45 - ext/picotcp/rules/6lowpan.mk | 62 - ext/picotcp/rules/crc.mk | 1 - ext/picotcp/rules/cyassl.mk | 3 - ext/picotcp/rules/debug.mk | 207 - 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 | 3 - ext/picotcp/rules/icmp4.mk | 5 - ext/picotcp/rules/igmp.mk | 3 - ext/picotcp/rules/ipc.mk | 1 - 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 | 2 - 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 | 482 -- ext/picotcp/stack/pico_frame.c | 329 -- ext/picotcp/stack/pico_md5.c | 43 - ext/picotcp/stack/pico_protocol.c | 227 - ext/picotcp/stack/pico_socket.c | 2289 -------- ext/picotcp/stack/pico_socket_multicast.c | 1478 ----- ext/picotcp/stack/pico_stack.c | 969 ---- ext/picotcp/stack/pico_tree.c | 565 -- ext/picotcp/test/Makefile | 10 - ext/picotcp/test/README.md | 6 - ext/picotcp/test/autotest.sh | 360 -- ext/picotcp/test/coverage.sh | 4 - ext/picotcp/test/dummy.c | 12 - ext/picotcp/test/examples/Makefile | 36 - ext/picotcp/test/examples/dhcp_client.c | 114 - ext/picotcp/test/examples/dhcp_server.c | 99 - ext/picotcp/test/examples/dns_sd.c | 112 - ext/picotcp/test/examples/dnsclient.c | 120 - ext/picotcp/test/examples/iperfc.c | 142 - ext/picotcp/test/examples/mdns.c | 83 - .../test/examples/multicast_ip6_recv.c | 182 - .../test/examples/multicast_ip6_send.c | 140 - ext/picotcp/test/examples/multicast_recv.c | 171 - ext/picotcp/test/examples/multicast_send.c | 129 - ext/picotcp/test/examples/natbox.c | 31 - ext/picotcp/test/examples/noop.c | 11 - ext/picotcp/test/examples/ping.c | 138 - ext/picotcp/test/examples/slaacv4.c | 72 - ext/picotcp/test/examples/sntp.c | 59 - ext/picotcp/test/examples/tcpbench.c | 320 -- ext/picotcp/test/examples/tcpclient.c | 197 - ext/picotcp/test/examples/tcpecho.c | 178 - ext/picotcp/test/examples/tftp.c | 485 -- ext/picotcp/test/examples/udp_client.c | 290 - ext/picotcp/test/examples/udp_echo.c | 216 - ext/picotcp/test/examples/udp_sendto_test.c | 88 - ext/picotcp/test/examples/udpnat.c | 151 - ext/picotcp/test/examples/utils.h | 39 - ext/picotcp/test/mkunits.sh | 104 - ext/picotcp/test/olsr_test.sh | 68 - ext/picotcp/test/perf.sh | 26 - ext/picotcp/test/pico_faulty.c | 29 - ext/picotcp/test/pico_faulty.h | 134 - ext/picotcp/test/picoapp.c | 757 --- ext/picotcp/test/ppp.c | 193 - ext/picotcp/test/python/dhcp.py | 36 - ext/picotcp/test/python/fairness.py | 48 - .../test/python/fairness_bottleneck.py | 47 - .../test/python/fairness_bottleneck_linux.py | 47 - ext/picotcp/test/python/fragmentation.py | 60 - ext/picotcp/test/python/howto.py | 135 - ext/picotcp/test/python/http_server_linux.py | 13 - ext/picotcp/test/python/multicast_recv.py | 64 - ext/picotcp/test/python/multicast_send.py | 58 - ext/picotcp/test/python/noop.py | 14 - ext/picotcp/test/python/ping.py | 14 - ext/picotcp/test/python/ping_delay.py | 14 - ext/picotcp/test/python/ping_linux.py | 14 - ext/picotcp/test/python/ping_nat.py | 17 - ext/picotcp/test/python/reassembly.py | 62 - ext/picotcp/test/python/tcpbench-delay.py | 18 - ext/picotcp/test/python/tcpbench-tap.py | 17 - ext/picotcp/test/python/tcpbench.py | 17 - ext/picotcp/test/python/tcpbench_rx_linux.py | 14 - ext/picotcp/test/python/tcpbench_tx_linux.py | 15 - ext/picotcp/test/python/tcpecho_linux.py | 16 - ext/picotcp/test/python/topology.py | 223 - .../test/python/traceroute_from_linux.py | 45 - .../test/python/traceroute_nat_from_linux.py | 45 - ext/picotcp/test/python/udpecho.py | 16 - ext/picotcp/test/python/zmq_linux.py | 34 - ext/picotcp/test/test_tftp_app_client.c | 244 - ext/picotcp/test/unit/modunit_pico_6lowpan.c | 1634 ------ ext/picotcp/test/unit/modunit_pico_802154.c | 556 -- ext/picotcp/test/unit/modunit_pico_aodv.c | 545 -- ext/picotcp/test/unit/modunit_pico_dev_loop.c | 97 - ext/picotcp/test/unit/modunit_pico_dev_ppp.c | 1387 ----- .../test/unit/modunit_pico_dns_client.c | 229 - .../test/unit/modunit_pico_dns_common.c | 1446 ----- ext/picotcp/test/unit/modunit_pico_dns_sd.c | 403 -- ext/picotcp/test/unit/modunit_pico_ethernet.c | 315 - .../test/unit/modunit_pico_fragments.c | 1234 ---- ext/picotcp/test/unit/modunit_pico_frame.c | 274 - .../unit/modunit_pico_hotplug_detection.c | 192 - ext/picotcp/test/unit/modunit_pico_igmp.c | 359 -- ext/picotcp/test/unit/modunit_pico_ipfilter.c | 321 -- ext/picotcp/test/unit/modunit_pico_ipv6_nd.c | 289 - ext/picotcp/test/unit/modunit_pico_mdns.c | 2227 ------- ext/picotcp/test/unit/modunit_pico_mld.c | 584 -- ext/picotcp/test/unit/modunit_pico_protocol.c | 229 - .../test/unit/modunit_pico_sntp_client.c | 428 -- ext/picotcp/test/unit/modunit_pico_stack.c | 145 - ext/picotcp/test/unit/modunit_pico_strings.c | 59 - ext/picotcp/test/unit/modunit_pico_tcp.c | 863 --- ext/picotcp/test/unit/modunit_pico_tftp.c | 375 -- ext/picotcp/test/unit/modunit_queue.c | 84 - ext/picotcp/test/unit/modunit_seq.c | 59 - ext/picotcp/test/unit/unit_arp.c | 213 - ext/picotcp/test/unit/unit_dhcp.c | 554 -- ext/picotcp/test/unit/unit_dns.c | 88 - ext/picotcp/test/unit/unit_icmp4.c | 401 -- ext/picotcp/test/unit/unit_ipv4.c | 852 --- ext/picotcp/test/unit/unit_ipv6.c | 760 --- ext/picotcp/test/unit/unit_mem_manager.c | 2158 ------- ext/picotcp/test/unit/unit_mocks.c | 71 - ext/picotcp/test/unit/unit_rbtree.c | 93 - ext/picotcp/test/unit/unit_socket.c | 521 -- ext/picotcp/test/unit/unit_timer.c | 40 - ext/picotcp/test/units.c | 233 - ext/picotcp/test/units.sh | 38 - ext/picotcp/test/vde_sock_start.sh | 22 - ext/picotcp/test/vde_sock_start_user.sh | 15 - ext/picotcp/uncrustify.cfg | 1579 ----- 393 files changed, 150665 deletions(-) delete mode 100644 ext/picotcp/.gitignore delete mode 100644 ext/picotcp/.travis.yml delete mode 100755 ext/picotcp/CONTRIBUTING.md delete mode 100644 ext/picotcp/COPYING delete mode 100644 ext/picotcp/LICENSE.GPLv2 delete mode 100644 ext/picotcp/LICENSE.GPLv3 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 100755 ext/picotcp/RFC/get_all_rfc delete mode 100644 ext/picotcp/RFC/rfc0813.txt delete mode 100644 ext/picotcp/RFC/rfc0814.txt delete mode 100644 ext/picotcp/RFC/rfc0816.txt delete mode 100644 ext/picotcp/RFC/rfc0817.txt delete mode 100644 ext/picotcp/RFC/rfc0826.txt delete mode 100644 ext/picotcp/RFC/rfc0872.txt delete mode 100644 ext/picotcp/RFC/rfc0879.txt delete mode 100644 ext/picotcp/RFC/rfc0896.txt delete mode 100644 ext/picotcp/RFC/rfc0964.txt delete mode 100644 ext/picotcp/RFC/rfc1071.txt delete mode 100644 ext/picotcp/RFC/rfc1072.txt delete mode 100644 ext/picotcp/RFC/rfc1106.txt delete mode 100644 ext/picotcp/RFC/rfc1110.txt delete mode 100644 ext/picotcp/RFC/rfc1146.txt delete mode 100644 ext/picotcp/RFC/rfc1156.txt delete mode 100644 ext/picotcp/RFC/rfc1180.txt delete mode 100644 ext/picotcp/RFC/rfc1185.txt delete mode 100644 ext/picotcp/RFC/rfc1213.txt delete mode 100644 ext/picotcp/RFC/rfc1263.txt delete mode 100644 ext/picotcp/RFC/rfc1332.txt delete mode 100644 ext/picotcp/RFC/rfc1334.txt delete mode 100644 ext/picotcp/RFC/rfc1337.txt delete mode 100644 ext/picotcp/RFC/rfc1350.txt delete mode 100644 ext/picotcp/RFC/rfc1624.txt delete mode 100644 ext/picotcp/RFC/rfc1662.txt delete mode 100644 ext/picotcp/RFC/rfc1877.txt delete mode 100644 ext/picotcp/RFC/rfc1936.txt delete mode 100644 ext/picotcp/RFC/rfc1948.txt delete mode 100644 ext/picotcp/RFC/rfc1994.txt delete mode 100644 ext/picotcp/RFC/rfc2012.txt delete mode 100644 ext/picotcp/RFC/rfc2018.txt delete mode 100644 ext/picotcp/RFC/rfc2132.txt delete mode 100644 ext/picotcp/RFC/rfc2140.txt delete mode 100644 ext/picotcp/RFC/rfc2347.txt delete mode 100644 ext/picotcp/RFC/rfc2349.txt delete mode 100644 ext/picotcp/RFC/rfc2385.txt delete mode 100644 ext/picotcp/RFC/rfc2398.txt delete mode 100644 ext/picotcp/RFC/rfc2415.txt delete mode 100644 ext/picotcp/RFC/rfc2416.txt delete mode 100644 ext/picotcp/RFC/rfc2452.txt delete mode 100644 ext/picotcp/RFC/rfc2474.txt delete mode 100644 ext/picotcp/RFC/rfc2488.txt delete mode 100644 ext/picotcp/RFC/rfc2581.txt delete mode 100644 ext/picotcp/RFC/rfc2675.txt delete mode 100644 ext/picotcp/RFC/rfc2861.txt delete mode 100644 ext/picotcp/RFC/rfc2873.txt delete mode 100644 ext/picotcp/RFC/rfc2883.txt delete mode 100644 ext/picotcp/RFC/rfc2884.txt delete mode 100644 ext/picotcp/RFC/rfc2914.txt delete mode 100644 ext/picotcp/RFC/rfc2923.txt delete mode 100644 ext/picotcp/RFC/rfc2988.txt delete mode 100644 ext/picotcp/RFC/rfc3042.txt delete mode 100644 ext/picotcp/RFC/rfc3124.txt delete mode 100644 ext/picotcp/RFC/rfc3150.txt delete mode 100644 ext/picotcp/RFC/rfc3155.txt delete mode 100644 ext/picotcp/RFC/rfc3360.txt delete mode 100644 ext/picotcp/RFC/rfc3366.txt delete mode 100644 ext/picotcp/RFC/rfc3390.txt delete mode 100644 ext/picotcp/RFC/rfc3465.txt delete mode 100644 ext/picotcp/RFC/rfc3481.txt delete mode 100644 ext/picotcp/RFC/rfc3517.txt delete mode 100644 ext/picotcp/RFC/rfc3522.txt delete mode 100644 ext/picotcp/RFC/rfc3540.txt delete mode 100644 ext/picotcp/RFC/rfc3562.txt delete mode 100644 ext/picotcp/RFC/rfc3708.txt delete mode 100644 ext/picotcp/RFC/rfc3742.txt delete mode 100644 ext/picotcp/RFC/rfc3782.txt delete mode 100644 ext/picotcp/RFC/rfc4015.txt delete mode 100644 ext/picotcp/RFC/rfc4022.txt delete mode 100644 ext/picotcp/RFC/rfc4138.txt delete mode 100644 ext/picotcp/RFC/rfc4278.txt delete mode 100644 ext/picotcp/docs/user_manual/README.md delete mode 100755 ext/picotcp/docs/user_manual/build.sh delete mode 100644 ext/picotcp/docs/user_manual/chap_api_aodv.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_dhcp_c.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_dhcp_d.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_dns_c.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_dns_sd.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_igmp.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_ipfilter.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_ipv4.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_ipv6.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_mdns.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_mld.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_olsr.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_ppp.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_slaacv4.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_sntp_c.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_sock.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_api_tftp.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_license.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_overview.tex delete mode 100644 ext/picotcp/docs/user_manual/chap_rfcs.tex delete mode 100644 ext/picotcp/docs/user_manual/layout.tex delete mode 100644 ext/picotcp/docs/user_manual/layout1.tex delete mode 100644 ext/picotcp/docs/user_manual/template_api.tex delete mode 100644 ext/picotcp/docs/user_manual/user_doc.tex delete mode 100644 ext/picotcp/docs/wiki_images/Protocol input.dia delete mode 100644 ext/picotcp/docs/wiki_images/Protocol output.dia delete mode 100644 ext/picotcp/docs/wiki_images/Protocol_input.png delete mode 100644 ext/picotcp/docs/wiki_images/Protocol_output.png delete mode 100644 ext/picotcp/docs/wiki_images/driver_stack_memory.dia delete mode 100644 ext/picotcp/docs/wiki_images/driver_stack_memory.png delete mode 100644 ext/picotcp/docs/wiki_images/petri_net.gif delete mode 100644 ext/picotcp/docs/wiki_images/picoTCP_logo.png delete mode 100644 ext/picotcp/docs/wiki_images/pico_frame.png delete mode 100644 ext/picotcp/docs/wiki_images/port_to_os.dia delete mode 100644 ext/picotcp/docs/wiki_images/port_to_os.png delete mode 100644 ext/picotcp/include/arch/pico_arm9.h delete mode 100644 ext/picotcp/include/arch/pico_atsamd21j18.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_dos.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_pic32.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_6lowpan.c delete mode 100644 ext/picotcp/modules/pico_6lowpan.h delete mode 100644 ext/picotcp/modules/pico_6lowpan_ll.c delete mode 100644 ext/picotcp/modules/pico_6lowpan_ll.h delete mode 100644 ext/picotcp/modules/pico_802154.c delete mode 100644 ext/picotcp/modules/pico_802154.h 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_ipc.c delete mode 100644 ext/picotcp/modules/pico_dev_ipc.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_radio_mgr.c delete mode 100644 ext/picotcp/modules/pico_dev_radio_mgr.h delete mode 100644 ext/picotcp/modules/pico_dev_radiotest.c delete mode 100644 ext/picotcp/modules/pico_dev_radiotest.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 100644 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_ethernet.c delete mode 100644 ext/picotcp/modules/pico_ethernet.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_mcast.c delete mode 100644 ext/picotcp/modules/pico_mcast.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/6lowpan.mk delete mode 100644 ext/picotcp/rules/crc.mk delete mode 100644 ext/picotcp/rules/cyassl.mk delete mode 100644 ext/picotcp/rules/debug.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/ipc.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/test/Makefile delete mode 100644 ext/picotcp/test/README.md delete mode 100755 ext/picotcp/test/autotest.sh delete mode 100755 ext/picotcp/test/coverage.sh delete mode 100644 ext/picotcp/test/dummy.c delete mode 100644 ext/picotcp/test/examples/Makefile delete mode 100644 ext/picotcp/test/examples/dhcp_client.c delete mode 100644 ext/picotcp/test/examples/dhcp_server.c delete mode 100644 ext/picotcp/test/examples/dns_sd.c delete mode 100644 ext/picotcp/test/examples/dnsclient.c delete mode 100644 ext/picotcp/test/examples/iperfc.c delete mode 100644 ext/picotcp/test/examples/mdns.c delete mode 100644 ext/picotcp/test/examples/multicast_ip6_recv.c delete mode 100644 ext/picotcp/test/examples/multicast_ip6_send.c delete mode 100644 ext/picotcp/test/examples/multicast_recv.c delete mode 100644 ext/picotcp/test/examples/multicast_send.c delete mode 100644 ext/picotcp/test/examples/natbox.c delete mode 100644 ext/picotcp/test/examples/noop.c delete mode 100644 ext/picotcp/test/examples/ping.c delete mode 100644 ext/picotcp/test/examples/slaacv4.c delete mode 100644 ext/picotcp/test/examples/sntp.c delete mode 100644 ext/picotcp/test/examples/tcpbench.c delete mode 100644 ext/picotcp/test/examples/tcpclient.c delete mode 100644 ext/picotcp/test/examples/tcpecho.c delete mode 100644 ext/picotcp/test/examples/tftp.c delete mode 100644 ext/picotcp/test/examples/udp_client.c delete mode 100644 ext/picotcp/test/examples/udp_echo.c delete mode 100644 ext/picotcp/test/examples/udp_sendto_test.c delete mode 100644 ext/picotcp/test/examples/udpnat.c delete mode 100644 ext/picotcp/test/examples/utils.h delete mode 100755 ext/picotcp/test/mkunits.sh delete mode 100755 ext/picotcp/test/olsr_test.sh delete mode 100755 ext/picotcp/test/perf.sh delete mode 100644 ext/picotcp/test/pico_faulty.c delete mode 100644 ext/picotcp/test/pico_faulty.h delete mode 100644 ext/picotcp/test/picoapp.c delete mode 100644 ext/picotcp/test/ppp.c delete mode 100755 ext/picotcp/test/python/dhcp.py delete mode 100755 ext/picotcp/test/python/fairness.py delete mode 100755 ext/picotcp/test/python/fairness_bottleneck.py delete mode 100755 ext/picotcp/test/python/fairness_bottleneck_linux.py delete mode 100755 ext/picotcp/test/python/fragmentation.py delete mode 100644 ext/picotcp/test/python/howto.py delete mode 100755 ext/picotcp/test/python/http_server_linux.py delete mode 100755 ext/picotcp/test/python/multicast_recv.py delete mode 100755 ext/picotcp/test/python/multicast_send.py delete mode 100755 ext/picotcp/test/python/noop.py delete mode 100755 ext/picotcp/test/python/ping.py delete mode 100755 ext/picotcp/test/python/ping_delay.py delete mode 100755 ext/picotcp/test/python/ping_linux.py delete mode 100755 ext/picotcp/test/python/ping_nat.py delete mode 100755 ext/picotcp/test/python/reassembly.py delete mode 100755 ext/picotcp/test/python/tcpbench-delay.py delete mode 100755 ext/picotcp/test/python/tcpbench-tap.py delete mode 100755 ext/picotcp/test/python/tcpbench.py delete mode 100755 ext/picotcp/test/python/tcpbench_rx_linux.py delete mode 100755 ext/picotcp/test/python/tcpbench_tx_linux.py delete mode 100755 ext/picotcp/test/python/tcpecho_linux.py delete mode 100755 ext/picotcp/test/python/topology.py delete mode 100755 ext/picotcp/test/python/traceroute_from_linux.py delete mode 100755 ext/picotcp/test/python/traceroute_nat_from_linux.py delete mode 100755 ext/picotcp/test/python/udpecho.py delete mode 100755 ext/picotcp/test/python/zmq_linux.py delete mode 100644 ext/picotcp/test/test_tftp_app_client.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_6lowpan.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_802154.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_aodv.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_dev_loop.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_dev_ppp.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_dns_client.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_dns_common.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_dns_sd.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_ethernet.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_fragments.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_frame.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_hotplug_detection.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_igmp.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_ipfilter.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_ipv6_nd.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_mdns.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_mld.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_protocol.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_sntp_client.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_stack.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_strings.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_tcp.c delete mode 100644 ext/picotcp/test/unit/modunit_pico_tftp.c delete mode 100644 ext/picotcp/test/unit/modunit_queue.c delete mode 100644 ext/picotcp/test/unit/modunit_seq.c delete mode 100644 ext/picotcp/test/unit/unit_arp.c delete mode 100644 ext/picotcp/test/unit/unit_dhcp.c delete mode 100644 ext/picotcp/test/unit/unit_dns.c delete mode 100644 ext/picotcp/test/unit/unit_icmp4.c delete mode 100644 ext/picotcp/test/unit/unit_ipv4.c delete mode 100644 ext/picotcp/test/unit/unit_ipv6.c delete mode 100644 ext/picotcp/test/unit/unit_mem_manager.c delete mode 100644 ext/picotcp/test/unit/unit_mocks.c delete mode 100644 ext/picotcp/test/unit/unit_rbtree.c delete mode 100644 ext/picotcp/test/unit/unit_socket.c delete mode 100644 ext/picotcp/test/unit/unit_timer.c delete mode 100644 ext/picotcp/test/units.c delete mode 100755 ext/picotcp/test/units.sh delete mode 100755 ext/picotcp/test/vde_sock_start.sh delete mode 100755 ext/picotcp/test/vde_sock_start_user.sh delete mode 100644 ext/picotcp/uncrustify.cfg 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/CONTRIBUTING.md b/ext/picotcp/CONTRIBUTING.md deleted file mode 100755 index a61f72f..0000000 --- a/ext/picotcp/CONTRIBUTING.md +++ /dev/null @@ -1,8 +0,0 @@ - -External contributions to picoTCP are very welcome. We do, however, ask that you sign the Contributor License Agreement. -We don't ask you to sign away your copyright. The CLA simply grants us an additional license on the code you wrote. This allows us to also use picoTCP in commercial projects, which enables us to keep investing time and money in creating a better TCP/IP stack. - -Please read the [Agreement](https://docs.google.com/forms/d/1-z6lsT75l6ZIrgHGEWrWdHylJ6xxpjc7FwGfL2ilDFU/viewform), and if you agree with it, fill in your information. -You will receive a mail with a timestamp. Please modify our [CLA confirmation page](https://github.com/tass-belgium/picotcp/wiki/picoTCP-CLA-Confirmation-Page), adding the timestamp and your github username. This way we can be sure that nobody else filled in your info in the form. - -Pull requests by people who haven't signed the CLA will, unfortunately, have to be rejected. diff --git a/ext/picotcp/COPYING b/ext/picotcp/COPYING deleted file mode 100644 index 9556096..0000000 --- a/ext/picotcp/COPYING +++ /dev/null @@ -1,8 +0,0 @@ -PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. - -Released under the GNU General Public License, version 2, or (at your option) -version 3. -See LICENSE.GPLv2 and LICENSE.GPLv3 for details. - -Different licensing models may exist, at the sole discretion of -the Copyright holders. diff --git a/ext/picotcp/LICENSE.GPLv2 b/ext/picotcp/LICENSE.GPLv2 deleted file mode 100644 index d159169..0000000 --- a/ext/picotcp/LICENSE.GPLv2 +++ /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/LICENSE.GPLv3 b/ext/picotcp/LICENSE.GPLv3 deleted file mode 100644 index 94a9ed0..0000000 --- a/ext/picotcp/LICENSE.GPLv3 +++ /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/ext/picotcp/MODTREE b/ext/picotcp/MODTREE deleted file mode 100644 index 27f9448..0000000 --- a/ext/picotcp/MODTREE +++ /dev/null @@ -1,27 +0,0 @@ -RTOS: -IPV4: ETH -IPV6: -DEVLOOP: -CRC: -ETH: -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 -AODV: IPV4 UDP -PPP: IPV4 -6LOWPAN: IPV6 -IEEE802154: 6LOWPAN diff --git a/ext/picotcp/Makefile b/ext/picotcp/Makefile deleted file mode 100644 index 78ec25b..0000000 --- a/ext/picotcp/Makefile +++ /dev/null @@ -1,508 +0,0 @@ --include ../../config.mk --include ../../tools/kconfig/.config - -OS:=$(shell uname) -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 -UNIT_LDFLAGS=-lcheck -lm -pthread -lrt -lsubunit -UNIT_CFLAGS= $(CFLAGS) -Wno-missing-braces - -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 -GCOV?=0 - -# 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 -6LOWPAN?=0 -IEEE802154?=0 -IPC?=0 -CYASSL?=0 -WOLFSSL?=0 -POLARSSL?=0 - -#IPv6 related -IPV6?=1 - -TEST?=0 -ifeq ($(TEST),1) - 6LOWPAN=1 - IEEE802154=1 -endif - -UNITS?=0 -ifeq ($(UNITS),1) - 6LOWPAN=1 - IEEE802154=1 - ARCH=faulty -endif - -UNITS_MM?=0 -ifeq ($(UNITS_MM),1) - 6LOWPAN=1 - IEEE802154=1 - MEMORY_MANAGER=1 -endif - -EXTRA_CFLAGS+=-DPICO_COMPILE_TIME=`date +%s` -EXTRA_CFLAGS+=$(PLATFORM_CFLAGS) - -CFLAGS=-I$(PREFIX)/include -Iinclude -Imodules $(EXTRA_CFLAGS) -# options for adding warnings -CFLAGS+= -Wall -W -Wextra -Wshadow -Wcast-qual -Wwrite-strings -Wundef -Wdeclaration-after-statement -CFLAGS+= -Wconversion -Wcast-align -Wmissing-prototypes -# options for supressing warnings -CFLAGS+= -Wno-missing-field-initializers - -ifeq ($(CC),clang) -CFLAGS+= -Wunreachable-code-break -Wpointer-bool-conversion -Wmissing-variable-declarations -endif - -ifeq ($(OS),Darwin) - LIBSIZE=stat -f%z - ifeq ($(SIZE),size) - SUMSIZE=$(SIZE) - else - SUMSIZE=$(SIZE) -t - endif -else - LIBSIZE=du -b - SUMSIZE=$(SIZE) -t -endif - -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),cortexm0plus) - CFLAGS+=-DCORTEX_M0PLUS -mcpu=cortex-m0plus -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 ($(GCOV),1) - TEST_LDFLAGS+=-lgcov --coverage - CFLAGS+=-fprofile-arcs -ftest-coverage -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),pic32) - CFLAGS+=-DPIC32 -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_ipc.o \ - modules/pico_dev_tap.o \ - modules/pico_dev_mock.o - -include rules/debug.mk - -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 ($(6LOWPAN), 0) - include rules/6lowpan.mk -endif -ifneq ($(IPC),0) - include rules/ipc.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 - @if [ $(TEST) -eq 0 ]; then \ - echo "\n\nsmoke tests should be compiled with TEST=1 from now on!"; \ - exit 1; \ - fi - @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] `$(LIBSIZE) $(PREFIX)/lib/$(LIBNAME)`" - @echo -e "`$(SUMSIZE) $(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) - @if [ $(UNITS) -eq 0 ]; then \ - echo "\n\nunit tests should be compiled with UNITS=1 from now on!"; \ - exit 1; \ - fi - @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 $(UNIT_CFLAGS) -I stack -I modules -I includes -I test/unit -DUNIT_TEST - @echo -e "\t[LD] $(PREFIX)/test/units" - @$(CC) -o $(PREFIX)/test/units $(UNIT_CFLAGS) $(PREFIX)/test/units.o $(UNIT_LDFLAGS) \ - $(UNITS_OBJ) $(PREFIX)/modules/pico_aodv.o \ - $(PREFIX)/modules/pico_fragments.o - @$(CC) -o $(PREFIX)/test/modunit_pico_protocol.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_protocol.c stack/pico_tree.c $(UNIT_LDFLAGS) $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_pico_frame.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_frame.c stack/pico_tree.c $(UNIT_LDFLAGS) $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_seq.elf $(UNIT_CFLAGS) -I. test/unit/modunit_seq.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_tcp.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_tcp.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_client.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dns_client.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_common.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dns_common.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_mdns.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_mdns.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dns_sd.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dev_loop.c $(UNIT_LDFLAGS) $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_ethernet.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_ethernet.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_stack.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_tftp.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_sntp_client.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_sntp_client.c $(UNIT_LDFLAGS) $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_ipfilter.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_ipfilter.c stack/pico_tree.c $(UNIT_LDFLAGS) $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_aodv.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_aodv.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_fragments.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_fragments.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_queue.elf $(UNIT_CFLAGS) -I. test/unit/modunit_queue.c $(UNIT_LDFLAGS) $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_dev_ppp.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dev_ppp.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_mld.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_mld.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_igmp.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_igmp.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_hotplug_detection.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_hotplug_detection.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_802154.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_802154.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_6lowpan.elf $(UNIT_CFLAGS) -I. -I test/examples test/unit/modunit_pico_6lowpan.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a - @$(CC) -o $(PREFIX)/test/modunit_strings.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_strings.c $(UNIT_LDFLAGS) $(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 - @if [ $(UNITS_MM) -eq 0 ]; then \ - echo "\n\nMM unit tests should be compiled with UNITS_MM=1 from now on!"; \ - exit 1; \ - fi - @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 uncrustify --replace -l C -c uncrustify.cfg || true - @find . -iname "*unc-backup*" |xargs 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 $(PREFIX)/include/ -I $(PREFIX)/modules/ $(CFLAGS) - gcc -o ppp ppp.o $(PREFIX)/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS) - rm -f ppp.o - -.PHONY: coverity -coverity: - @make clean - @cov-build --dir $(PREFIX)/cov-int make - @tar czvf $(PREFIX)/coverity.tgz -C $(PREFIX) cov-int - -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 4cce9ab..0000000 --- a/ext/picotcp/README.md +++ /dev/null @@ -1,220 +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 and GNU GPL v3. 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 - -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) - -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) - -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) - -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) - ---------------- - -## Simple example - -### Preparations -This example uses Ubuntu 14.04. It works on other linux distibutions as well, though you may need to change some package names. See [setting up the environment](https://github.com/tass-belgium/picotcp/wiki/Setting-up-the-environment#prerequisite-packages) for some more info. - -```bash -sudo apt-get install git check vde2 libvdeplug2-dev libpcap0.8-dev openvpn wireshark -git clone https://github.com/tass-belgium/picotcp -cd picotcp -make TAP=1 -cd .. -``` - -### The code - -Then make a new directory, e.g. `example`, and create a file with the following content : -[//]: # (The code below is pulled through our CI - please leave the code extractor comments intact!) -[//]: # (code extractor start) -```C -#include -#include -#include -#include -#include - -#define NUM_PING 10 - -static int finished = 0; - -/* gets called when the ping receives a reply, or encounters a problem */ -void cb_ping(struct pico_icmp4_stats *s) -{ - char host[30]; - pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - /* if all is well, print some pretty info */ - 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); - if (s->seq >= NUM_PING) - finished = 1; - } else { - /* if something went wrong, print it and signal we want to stop */ - printf("PING %lu to %s: Error %d\n", s->seq, host, s->err); - finished = 1; - } -} - - -int main(void){ - int id; - struct pico_ip4 ipaddr, netmask; - struct pico_device* dev; - - /* initialise the stack. Super important if you don't want ugly stuff like - * segfaults and such! */ - pico_stack_init(); - - /* create the tap device */ - dev = pico_tap_create("tap0"); - if (!dev) - return -1; - - /* assign the IP address to the tap interface */ - pico_string_to_ipv4("192.168.5.4", &ipaddr.addr); - pico_string_to_ipv4("255.255.255.0", &netmask.addr); - pico_ipv4_link_add(dev, ipaddr, netmask); - - printf("starting ping\n"); - id = pico_icmp4_ping("192.168.5.5", NUM_PING, 1000, 10000, 64, cb_ping); - - if (id == -1) - return -1; - - /* keep running stack ticks to have picoTCP do its network magic. Note that - * you can do other stuff here as well, or sleep a little. This will impact - * your network performance, but everything should keep working (provided - * you don't go overboard with the delays). */ - while (finished != 1) - { - usleep(1000); - pico_stack_tick(); - } - - printf("finished !\n"); - return 0; -} - -``` - -[//]: # (code extractor stop) - -### Building and running - -Now we can compile this and link it, by running -```bash -gcc -c -o main.o -I../picotcp/build/include main.c -gcc -o main.elf main.o ../picotcp/build/lib/libpicotcp.a -``` - -Next we'll create a persistent tap device - a virtual network port. You don't need to repeat this each time, the device will exist until you reboot, or until you go `sudo tunctl -d tap0` -```bash -sudo tunctl -u -sudo ifconfig tap0 192.168.5.5 -``` - -Now, you should be able to run `./main.elf`, and see output like -``` -Protocol ethernet registered (layer: 2). -Protocol ipv4 registered (layer: 3). -Protocol ipv6 registered (layer: 3). -Protocol icmp4 registered (layer: 4). -Protocol icmp6 registered (layer: 4). -Protocol igmp registered (layer: 4). -Protocol udp registered (layer: 4). -Protocol tcp registered (layer: 4). -Device tap0 created. -Assigned ipv4 192.168.5.4 to device tap0 -starting ping -64 bytes from 192.168.5.5: icmp_req=1 ttl=64 time=5 ms -64 bytes from 192.168.5.5: icmp_req=2 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=3 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=4 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=5 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=6 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=7 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=8 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=9 ttl=64 time=0 ms -64 bytes from 192.168.5.5: icmp_req=10 ttl=64 time=0 ms -finished ! -``` - -While the application is running, you can also run -``` -ping 192.168.5.4 -``` -to send pings in the other direction. - -### Investigating what happened - -Run wireshark, and sniff the tap0 interface. Then run the `./main.elf` again, and see what happens. You should see an ARP request from picoTCP to Linux, and a reply. After that you should see the ping requests and replies going back and forth. - -Note, sometimes you may see lots of other stuff, IPv6 router sollicitations, various broadcasts, mDNS, DNS-SD, etc - this is your when your Linux notices the new network interface is up, and starts all sorts of discoveries. With the persistent TAP device, this usually only happens the first time you start the application. Start a new wireshark capture, and start the application again, it should be much cleaner now. - -Now you could make some changes to the `main.c` file, and experiment a bit! Keep some statistics of your pings (max, min, avg time). Open a UDP socket, send some stuff to a netcat instance on your linux. Or build a rudimentary port scanner, see what ports are open on your machine. - - -This is just a very quick overview, more info can be found in our [wiki](https://github.com/tass-belgium/picotcp/wiki). - ---------------- - -## Contributors - -Contributors are very welcome. Report a bug, suggest a way to improve our documentation, or write some new code. - -Note however that, before accepting your code, we would ask you to sign our [Contributors License Agreement](https://docs.google.com/forms/d/1-z6lsT75l6ZIrgHGEWrWdHylJ6xxpjc7FwGfL2ilDFU/viewform). Your code remains under your copyright, and will always be available under GPLv2 and GPLv3. However, this CLA enables us to use picoTCP (including code from external contributors like you) under other licenses, including our commercial license. By doing commercial projects, we can keep investing in the quality and features of picoTCP. - ---------------- - -## PicoTCP has been used with - -**Platforms picoTCP runs on**: -ARM Cortex-M series (ST Micro STM, NXP LPC, TI Stellaris, Freescale K64F), -ARM ARM9-series (ST Micro STR9), -Texas Instruments (MSP430), -Microchip (PIC24, PIC32), -Atmel (AVR 8bit), -Linux (User space (TUN/TAP), Kernel space), -Windows (User space (TAP)) - -**Network devices picoTCP has worked with**: -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 picoTCP has been integrated into**: -No OS / Bare metal, FreeRTOS, mbed-RTOS, Frosted, linux / POSIX, MS DOS, MS Windows - -**Libraries picoTCP has been integrated with**: -wolfSSL, mbedTLS, Mongoose RESTful library, MicroPython - -**Compilers picoTCP compiles under**: -GCC, Clang, TCC, ARM-RCVT, IAR, XC-16, XC-32, MSP-GCC, AVR-GCC - -Unfortunately we can't release all the code, a.o. because some parts depend on code or binaries that aren't GPL compatible, some parts were developed under a commercial contract, and some consist of very rough proof-of-concept code. -If you want to know more about the availability under the commercial license, or the possibility of using our expert services for porting or driver development, feel free to contact us at info@picotcp.com. - -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/RFC/get_all_rfc b/ext/picotcp/RFC/get_all_rfc deleted file mode 100755 index 701bba4..0000000 --- a/ext/picotcp/RFC/get_all_rfc +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -wget -O rfc4614.txt http://tools.ietf.org/rfc/rfc4614.txt - - -for RFC in `grep "\[RFC" rfc4614.txt | sed -e "s/^.*RFC/rfc/" | grep -v "rfc \|rfc$" | sed -e "s/\].*$/.txt/g" |sort |uniq`; do - wget -O ${RFC} http://tools.ietf.org/rfc/${RFC} -done - -wget -O rfc3927.txt http://tools.ietf.org/rfc/rfc3927.txt - -# Get PPP related RFC's -for RFC in $(echo 1332 1334 1661 1662 1877 1994 | sed -r "s/[^ ]+/rfc&.txt/g"); do - wget -O ${RFC} http://tools.ietf.org/rfc/${RFC} -done diff --git a/ext/picotcp/RFC/rfc0813.txt b/ext/picotcp/RFC/rfc0813.txt deleted file mode 100644 index 5817050..0000000 --- a/ext/picotcp/RFC/rfc0813.txt +++ /dev/null @@ -1,1167 +0,0 @@ - -RFC: 813 - - - - WINDOW AND ACKNOWLEDGEMENT STRATEGY IN TCP - - David D. Clark - MIT Laboratory for Computer Science - Computer Systems and Communications Group - July, 1982 - - - 1. Introduction - - - This document describes implementation strategies to deal with two - -mechanisms in TCP, the window and the acknowledgement. These mechanisms - -are described in the specification document, but it is possible, while - -complying with the specification, to produce implementations which yield - -very bad performance. Happily, the pitfalls possible in window and - -acknowledgement strategies are very easy to avoid. - - - It is a much more difficult exercise to verify the performance of a - -specification than the correctness. Certainly, we have less experience - -in this area, and we certainly lack any useful formal technique. - -Nonetheless, it is important to attempt a specification in this area, - -because different implementors might otherwise choose superficially - -reasonable algorithms which interact poorly with each other. This - -document presents a particular set of algorithms which have received - -testing in the field, and which appear to work properly with each other. - -With more experience, these algorithms may become part of the formal - -specification: until such time their use is recommended. - - 2 - - -2. The Mechanisms - - - The acknowledgement mechanism is at the heart of TCP. Very simply, - -when data arrives at the recipient, the protocol requires that it send - -back an acknowledgement of this data. The protocol specifies that the - -bytes of data are sequentially numbered, so that the recipient can - -acknowledge data by naming the highest numbered byte of data it has - -received, which also acknowledges the previous bytes (actually, it - -identifies the first byte of data which it has not yet received, but - -this is a small detail). The protocol contains only a general assertion - -that data should be acknowledged promptly, but gives no more specific - -indication as to how quickly an acknowledgement must be sent, or how - -much data should be acknowledged in each separate acknowledgement. - - - The window mechanism is a flow control tool. Whenever appropriate, - -the recipient of data returns to the sender a number, which is (more or - -less) the size of the buffer which the receiver currently has available - -for additional data. This number of bytes, called the window, is the - -maximum which the sender is permitted to transmit until the receiver - -returns some additional window. Sometimes, the receiver will have no - -buffer space available, and will return a window value of zero. Under - -these circumstances,the protocol requires the sender to send a small - -segment to the receiver now and then, to see if more data is accepted. - -If the window remains closed at zero for some substantial period, and - -the sender can obtain no response from the receiver, the protocol - -requires the sender to conclude that the receiver has failed, and to - -close the connection. Again, there is very little performance - - 3 - - -information in the specification, describing under what circumstances - -the window should be increased, and how the sender should respond to - -such revised information. - - - A bad implementation of the window algorithm can lead to extremely - -poor performance overall. The degradations which occur in throughput - -and CPU utilizations can easily be several factors of ten, not just a - -fractional increase. This particular phenomenon is specific enough that - -it has been given the name of Silly Window Syndrome, or SWS. Happily - -SWS is easy to avoid if a few simple rules are observed. The most - -important function of this memo is to describe SWS, so that implementors - -will understand the general nature of the problem, and to describe - -algorithms which will prevent its occurrence. This document also - -describes performance enhancing algorithms which relate to - -acknowledgement, and discusses the way acknowledgement and window - -algorithms interact as part of SWS. - - - 3. SILLY WINDOW SYNDROME - - - In order to understand SWS, we must first define two new terms. - -Superficially, the window mechanism is very simple: there is a number, - -called "the window", which is returned from the receiver to the sender. - -However, we must have a more detailed way of talking about the meaning - -of this number. The receiver of data computes a value which we will - -call the "offered window". In a simple case, the offered window - -corresponds to the amount of buffer space available in the receiver. - -This correspondence is not necessarily exact, but is a suitable model - -for the discussion to follow. It is the offered window which is - - 4 - - -actually transmitted back from the receiver to the sender. The sender - -uses the offered window to compute a different value, the "usable - -window", which is the offered window minus the amount of outstanding - -unacknowledged data. The usable window is less than or equal to the - -offered window, and can be much smaller. - - - Consider the following simple example. The receiver initially - -provides an offered window of 1,000. The sender uses up this window by - -sending five segments of 200 bytes each. The receiver, on processing - -the first of these segments, returns an acknowledgement which also - -contains an updated window value. Let us assume that the receiver of - -the data has removed the first 200 bytes from the buffer, so that the - -receiver once again has 1,000 bytes of available buffer. Therefore, the - -receiver would return, as before, an offered window of 1,000 bytes. The - -sender, on receipt of this first acknowledgement, now computes the - -additional number of bytes which may be sent. In fact, of the 1,000 - -bytes which the recipient is prepared to receive at this time, 800 are - -already in transit, having been sent in response to the previous offered - -window. In this case, the usable window is only 200 bytes. - - - Let us now consider how SWS arises. To continue the previous - -example, assume that at some point, when the sender computes a useable - -window of 200 bytes, it has only 50 bytes to send until it reaches a - -"push" point. It thus sends 50 bytes in one segment, and 150 bytes in - -the next segment. Sometime later, this 50-byte segment will arrive at - -the recipient, which will process and remove the 50 bytes and once again - -return an offered window of 1,000 bytes. However, the sender will now - - 5 - - -compute that there are 950 bytes in transit in the network, so that the - -useable window is now only 50 bytes. Thus, the sender will once again - -send a 50 byte segment, even though there is no longer a natural - -boundary to force it. - - - In fact, whenever the acknowledgement of a small segment comes - -back, the useable window associated with that acknowledgement will cause - -another segment of the same small size to be sent, until some - -abnormality breaks the pattern. It is easy to see how small segments - -arise, because natural boundaries in the data occasionally cause the - -sender to take a computed useable window and divide it up between two - -segments. Once that division has occurred, there is no natural way for - -those useable window allocations to be recombined; thus the breaking up - -of the useable window into small pieces will persist. - - - Thus, SWS is a degeneration in the throughput which develops over - -time, during a long data transfer. If the sender ever stops, as for - -example when it runs out of data to send, the receiver will eventually - -acknowledge all the outstanding data, so that the useable window - -computed by the sender will equal the full offered window of the - -receiver. At this point the situation will have healed, and further - -data transmission over the link will occur efficiently. However, in - -large file transfers, which occur without interruption, SWS can cause - -appalling performance. The network between the sender and the receiver - -becomes clogged with many small segments, and an equal number of - -acknowledgements, which in turn causes lost segments, which triggers - -massive retransmission. Bad cases of SWS have been seen in which the - - 6 - - -average segment size was one-tenth of the size the sender and receiver - -were prepared to deal with, and the average number of retransmission per - -successful segments sent was five. - - - Happily, SWS is trivial to avoid. The following sections describe - -two algorithms, one executed by the sender, and one by the receiver, - -which appear to eliminate SWS completely. Actually, either algorithm by - -itself is sufficient to prevent SWS, and thus protect a host from a - -foreign implementation which has failed to deal properly with this - -problem. The two algorithms taken together produce an additional - -reduction in CPU consumption, observed in practice to be as high as a - -factor of four. - - - 4. Improved Window Algorithms - - - The receiver of data can take a very simple step to eliminate SWS. - -When it disposes of a small amount of data, it can artificially reduce - -the offered window in subsequent acknowledgements, so that the useable - -window computed by the sender does not permit the sending of any further - -data. At some later time, when the receiver has processed a - -substantially larger amount of incoming data, the artificial limitation - -on the offered window can be removed all at once, so that the sender - -computes a sudden large jump rather than a sequence of small jumps in - -the useable window. - - - At this level, the algorithm is quite simple, but in order to - -determine exactly when the window should be opened up again, it is - -necessary to look at some of the other details of the implementation. - - 7 - - -Depending on whether the window is held artificially closed for a short - -or long time, two problems will develop. The one we have already - -discussed -- never closing the window artificially -- will lead to SWS. - -On the other hand, if the window is only opened infrequently, the - -pipeline of data in the network between the sender and the receiver may - -have emptied out while the sender was being held off, so that a delay is - -introduced before additional data arrives from the sender. This delay - -does reduce throughput, but it does not consume network resources or CPU - -resources in the process, as does SWS. Thus, it is in this direction - -that one ought to overcompensate. For a simple implementation, a rule - -of thumb that seems to work in practice is to artificially reduce the - -offered window until the reduction constitutes one half of the available - -space, at which point increase the window to advertise the entire space - -again. In any event, one ought to make the chunk by which the window is - -opened at least permit one reasonably large segment. (If the receiver - -is so short of buffers that it can never advertise a large enough buffer - -to permit at least one large segment, it is hopeless to expect any sort - -of high throughput.) - - - There is an algorithm that the sender can use to achieve the same - -effect described above: a very simple and elegant rule first described - -by Michael Greenwald at MIT. The sender of the data uses the offered - -window to compute a useable window, and then compares the useable window - -to the offered window, and refrains from sending anything if the ratio - -of useable to offered is less than a certain fraction. Clearly, if the - -computed useable window is small compared to the offered window, this - -means that a substantial amount of previously sent information is still - - 8 - - -in the pipeline from the sender to the receiver, which in turn means - -that the sender can count on being granted a larger useable window in - -the future. Until the useable window reaches a certain amount, the - -sender should simply refuse to send anything. - - - Simple experiments suggest that the exact value of the ratio is not - -very important, but that a value of about 25 percent is sufficient to - -avoid SWS and achieve reasonable throughput, even for machines with a - -small offered window. An additional enhancement which might help - -throughput would be to attempt to hold off sending until one can send a - -maximum size segment. Another enhancement would be to send anyway, even - -if the ratio is small, if the useable window is sufficient to hold the - -data available up to the next "push point". - - - This algorithm at the sender end is very simple. Notice that it is - -not necessary to set a timer to protect against protocol lockup when - -postponing the send operation. Further acknowledgements, as they - -arrive, will inevitably change the ratio of offered to useable window. - -(To see this, note that when all the data in the catanet pipeline has - -arrived at the receiver, the resulting acknowledgement must yield an - -offered window and useable window that equal each other.) If the - -expected acknowledgements do not arrive, the retransmission mechanism - -will come into play to assure that something finally happens. Thus, to - -add this algorithm to an existing TCP implementation usually requires - -one line of code. As part of the send algorithm it is already necessary - -to compute the useable window from the offered window. It is a simple - -matter to add a line of code which, if the ratio is less than a certain - - 9 - - -percent, sets the useable window to zero. The results of SWS are so - -devastating that no sender should be without this simple piece of - -insurance. - - - 5. Improved Acknowledgement Algorithms - - - In the beginning of this paper, an overly simplistic implementation - -of TCP was described, which led to SWS. One of the characteristics of - -this implementation was that the recipient of data sent a separate - -acknowledgement for every segment that it received. This compulsive - -acknowledgement was one of the causes of SWS, because each - -acknowledgement provided some new useable window, but even if one of the - -algorithms described above is used to eliminate SWS, overly frequent - -acknowledgement still has a substantial problem, which is that it - -greatly increases the processing time at the sender's end. Measurement - -of TCP implementations, especially on large operating systems, indicate - -that most of the overhead of dealing with a segment is not in the - -processing at the TCP or IP level, but simply in the scheduling of the - -handler which is required to deal with the segment. A steady dribble of - -acknowledgements causes a high overhead in scheduling, with very little - -to show for it. This waste is to be avoided if possible. - - - There are two reasons for prompt acknowledgement. One is to - -prevent retransmission. We will discuss later how to determine whether - -unnecessary retransmission is occurring. The other reason one - -acknowledges promptly is to permit further data to be sent. However, - -the previous section makes quite clear that it is not always desirable - -to send a little bit of data, even though the receiver may have room for - - 10 - - -it. Therefore, one can state a general rule that under normal - -operation, the receiver of data need not, and for efficiency reasons - -should not, acknowledge the data unless either the acknowledgement is - -intended to produce an increased useable window, is necessary in order - -to prevent retransmission or is being sent as part of a reverse - -direction segment being sent for some other reason. We will consider an - -algorithm to achieve these goals. - - - Only the recipient of the data can control the generation of - -acknowledgements. Once an acknowledgement has been sent from the - -receiver back to the sender, the sender must process it. Although the - -extra overhead is incurred at the sender's end, it is entirely under the - -receiver's control. Therefore, we must now describe an algorithm which - -occurs at the receiver's end. Obviously, the algorithm must have the - -following general form; sometimes the receiver of data, upon processing - -a segment, decides not to send an acknowledgement now, but to postpone - -the acknowledgement until some time in the future, perhaps by setting a - -timer. The peril of this approach is that on many large operating - -systems it is extremely costly to respond to a timer event, almost as - -costly as to respond to an incoming segment. Clearly, if the receiver - -of the data, in order to avoid extra overhead at the sender end, spends - -a great deal of time responding to timer interrupts, no overall benefit - -has been achieved, for efficiency at the sender end is achieved by great - -thrashing at the receiver end. We must find an algorithm that avoids - -both of these perils. - - - The following scheme seems a good compromise. The receiver of data - - 11 - - -will refrain from sending an acknowledgement under certain - -circumstances, in which case it must set a timer which will cause the - -acknowledgement to be sent later. However, the receiver should do this - -only where it is a reasonable guess that some other event will intervene - -and prevent the necessity of the timer interrupt. The most obvious - -event on which to depend is the arrival of another segment. So, if a - -segment arrives, postpone sending an acknowledgement if both of the - -following conditions hold. First, the push bit is not set in the - -segment, since it is a reasonable assumption that there is more data - -coming in a subsequent segment. Second, there is no revised window - -information to be sent back. - - - This algorithm will insure that the timer, although set, is seldom - -used. The interval of the timer is related to the expected inter- - -segment delay, which is in turn a function of the particular network - -through which the data is flowing. For the Arpanet, a reasonable - -interval seems to be 200 to 300 milliseconds. Appendix A describes an - -adaptive algorithm for measuring this delay. - - - The section on improved window algorithms described both a receiver - -algorithm and a sender algorithm, and suggested that both should be - -used. The reason for this is now clear. While the sender algorithm is - -extremely simple, and useful as insurance, the receiver algorithm is - -required in order that this improved acknowledgement strategy work. If - -the receipt of every segment causes a new window value to be returned, - -then of necessity an acknowledgement will be sent for every data - -segment. When, according to the strategy of the previous section, the - - 12 - - -receiver determines to artificially reduce the offered window, that is - -precisely the circumstance under which an acknowledgement need not be - -sent. When the receiver window algorithm and the receiver - -acknowledgement algorithm are used together, it will be seen that - -sending an acknowledgement will be triggered by one of the following - -events. First, a push bit has been received. Second, a temporary pause - -in the data stream is detected. Third, the offered window has been - -artificially reduced to one-half its actual value. - - - In the beginning of this section, it was pointed out that there are - -two reasons why one must acknowledge data. Our consideration at this - -point has been concerned only with the first, that an acknowledgement - -must be returned as part of triggering the sending of new data. It is - -also necessary to acknowledge whenever the failure to do so would - -trigger retransmission by the sender. Since the retransmission interval - -is selected by the sender, the receiver of the data cannot make a - -precise determination of when the acknowledgement must be sent. - -However, there is a rough rule the sender can use to avoid - -retransmission, provided that the receiver is reasonably well behaved. - - - We will assume that sender of the data uses the optional algorithm - -described in the TCP specification, in which the roundtrip delay is - -measured using an exponential decay smoothing algorithm. Retransmission - -of a segment occurs if the measured delay for that segment exceeds the - -smoothed average by some factor. To see how retransmission might be - -triggered, one must consider the pattern of segment arrivals at the - -receiver. The goal of our strategy was that the sender should send off - - 13 - - -a number of segments in close sequence, and receive one acknowledgement - -for the whole burst. The acknowledgement will be generated by the - -receiver at the time that the last segment in the burst arrives at the - -receiver. (To ensure the prompt return of the acknowledgement, the - -sender could turn on the "push" bit in the last segment of the burst.) - -The delay observed at the sender between the initial transmission of a - -segment and the receipt of the acknowledgement will include both the - -network transit time, plus the holding time at the receiver. The - -holding time will be greatest for the first segments in the burst, and - -smallest for the last segments in the burst. Thus, the smoothing - -algorithm will measure a delay which is roughly proportional to the - -average roundtrip delay for all the segments in the burst. Problems - -will arise if the average delay is substantially smaller than the - -maximum delay and the smoothing algorithm used has a very small - -threshold for triggering retransmission. The widest variation between - -average and maximum delay will occur when network transit time is - -negligible, and all delay is processing time. In this case, the maximum - -will be twice the average (by simple algebra) so the threshold that - -controls retransmission should be somewhat more than a factor of two. - - - In practice, retransmission of the first segments of a burst has - -not been a problem because the delay measured consists of the network - -roundtrip delay, as well as the delay due to withholding the - -acknowledgement, and the roundtrip tends to dominate except in very low - -roundtrip time situations (such as when sending to one's self for test - -purposes). This low roundtrip situation can be covered very simply by - -including a minimum value below which the roundtrip estimate is not - -permitted to drop. - - 14 - - - In our experiments with this algorithm, retransmission due to - -faulty calculation of the roundtrip delay occurred only once, when the - -parameters of the exponential smoothing algorithm had been misadjusted - -so that they were only taking into account the last two or three - -segments sent. Clearly, this will cause trouble since the last two or - -three segments of any burst are the ones whose holding time at the - -receiver is minimal, so the resulting total estimate was much lower than - -appropriate. Once the parameters of the algorithm had been adjusted so - -that the number of segments taken into account was approximately twice - -the number of segments in a burst of average size, with a threshold - -factor of 1.5, no further retransmission has ever been identified due to - -this problem, including when sending to ourself and when sending over - -high delay nets. - - - 6. Conservative Vs. Optimistic Windows - - - According to the TCP specification, the offered window is presumed - -to have some relationship to the amount of data which the receiver is - -actually prepared to receive. However, it is not necessarily an exact - -correspondence. We will use the term "conservative window" to describe - -the case where the offered window is precisely no larger than the actual - -buffering available. The drawback to conservative window algorithms is - -that they can produce very low throughput in long delay situations. It - -is easy to see that the maximum input of a conservative window algorithm - -is one bufferfull every roundtrip delay in the net, since the next - -bufferfull cannot be launched until the updated window/acknowledgement - -information from the previous transmission has made the roundtrip. - - 15 - - - In certain cases, it may be possible to increase the overall - -throughput of the transmission by increasing the offered window over the - -actual buffer available at the receiver. Such a strategy we will call - -an "optimistic window" strategy. The optimistic strategy works if the - -network delivers the data to the recipient sufficiently slowly that it - -can process the data fast enough to keep the buffer from overflowing. - -If the receiver is faster than the sender, one could, with luck, permit - -an infinitely optimistic window, in which the sender is simply permitted - -to send full-speed. If the sender is faster than the receiver, however, - -and the window is too optimistic, then some segments will cause a buffer - -overflow, and will be discarded. Therefore, the correct strategy to - -implement an optimistic window is to increase the window size until - -segments start to be lost. This only works if it is possible to detect - -that the segment has been lost. In some cases, it is easy to do, - -because the segment is partially processed inside the receiving host - -before it is thrown away. In other cases, overflows may actually cause - -the network interface to be clogged, which will cause the segments to be - -lost elsewhere in the net. It is inadvisable to attempt an optimistic - -window strategy unless one is certain that the algorithm can detect the - -resulting lost segments. However, the increase in throughput which is - -possible from optimistic windows is quite substantial. Any systems with - -small buffer space should seriously consider the merit of optimistic - -windows. - - - The selection of an appropriate window algorithm is actually more - -complicated than even the above discussion suggests. The following - -considerations are not presented with the intention that they be - - 16 - - -incorporated in current implementations of TCP, but as background for - -the sophisticated designer who is attempting to understand how his TCP - -will respond to a variety of networks, with different speed and delay - -characteristics. The particular pattern of windows and acknowledgements - -sent from receiver to sender influences two characteristics of the data - -being sent. First, they control the average data rate. Clearly, the - -average rate of the sender cannot exceed the average rate of the - -receiver, or long-term buffer overflow will occur. Second, they - -influence the burstiness of the data coming from the sender. Burstiness - -has both advantages and disadvantages. The advantage of burstiness is - -that it reduces the CPU processing necessary to send the data. This - -follows from the observed fact, especially on large machines, that most - -of the cost of sending a segment is not the TCP or IP processing, but - -the scheduling overhead of getting started. - - - On the other hand, the disadvantage of burstiness is that it may - -cause buffers to overflow, either in the eventual recipient, which was - -discussed above, or in an intermediate gateway, a problem ignored in - -this paper. The algorithms described above attempts to strike a balance - -between excessive burstiness, which in the extreme cases can cause - -delays because a burst is not requested soon enough, and excessive - -fragmentation of the data stream into small segments, which we - -identified as Silly Window Syndrome. - - - Under conditions of extreme delay in the network, none of the - -algorithms described above will achieve adequate throughput. - -Conservative window algorithms have a predictable throughput limit, - - 17 - - -which is one windowfull per roundtrip delay. Attempts to solve this by - -optimistic window strategies may cause buffer overflows due to the - -bursty nature of the arriving data. A very sophisticated way to solve - -this is for the receiver, having measured by some means the roundtrip - -delay and intersegment arrival rate of the actual connection, to open - -his window, not in one optimistic increment of gigantic proportion, but - -in a number of smaller optimistic increments, which have been carefully - -spaced using a timer so that the resulting smaller bursts which arrive - -are each sufficiently small to fit into the existing buffers. One could - -visualize this as a number of requests flowing backwards through the net - -which trigger in return a number of bursts which flow back spaced evenly - -from the sender to the receiver. The overall result is that the - -receiver uses the window mechanism to control the burstiness of the - -arrivals, and the average rate. - - - To my knowledge, no such strategy has been implemented in any TCP. - -First, we do not normally have delays high enough to require this kind - -of treatment. Second, the strategy described above is probably not - -stable unless it is very carefully balanced. Just as buses on a single - -bus route tend to bunch up, bursts which start out equally spaced could - -well end up piling into each other, and forming the single large burst - -which the receiver was hoping to avoid. It is important to understand - -this extreme case, however, in order to understand the limits beyond - -which TCP, as normally implemented, with either conservative or simple - -optimistic windows can be expected to deliver throughput which is a - -reasonable percentage of the actual network capacity. - - 18 - - - 7. Conclusions - - - This paper describes three simple algorithms for performance - -enhancement in TCP, one at the sender end and two at the receiver. The - -sender algorithm is to refrain from sending if the useable window is - -smaller than 25 percent of the offered window. The receiver algorithms - -are first, to artificially reduce the offered window when processing new - -data if the resulting reduction does not represent more than some - -fraction, say 50 percent, of the actual space available, and second, to - -refrain from sending an acknowledgment at all if two simple conditions - -hold. - - - Either of these algorithms will prevent the worst aspects of Silly - -Window Syndrome, and when these algorithms are used together, they will - -produce substantial improvement in CPU utilization, by eliminating the - -process of excess acknowledgements. - - - Preliminary experiments with these algorithms suggest that they - -work, and work very well. Both the sender and receiver algorithms have - -been shown to eliminate SWS, even when talking to fairly silly - -algorithms at the other end. The Multics mailer, in particular, had - -suffered substantial attacks of SWS while sending large mail to a number - -of hosts. We believe that implementation of the sender side algorithm - -has eliminated every known case of SWS detected in our mailer. - -Implementation of the receiver side algorithm produced substantial - -improvements of CPU time when Multics was the sending system. Multics - -is a typical large operating system, with scheduling costs which are - -large compared to the actual processing time for protocol handlers. - - 19 - - -Tests were done sending from Multics to a host which implemented the SWS - -suppression algorithm, and which could either refrain or not from - -sending acknowledgements on each segment. As predicted, suppressing the - -return acknowledgements did not influence the throughput for large data - -transfer at all, since the throttling effect was elsewhere. However, - -the CPU time required to process the data at the Multics end was cut by - -a factor of four (In this experiment, the bursts of data which were - -being sent were approximately eight segments. Thus, the number of - -acknowledgements in the two experiments differed by a factor of eight.) - - - An important consideration in evaluating these algorithms is that - -they must not cause the protocol implementations to deadlock. All of - -the recommendations in this document have the characteristic that they - -suggest one refrain from doing something even though the protocol - -specification permits one to do it. The possibility exists that if one - -refrains from doing something now one may never get to do it later, and - -both ends will halt, even though it would appear superficially that the - -transaction can continue. - - - Formally, the idea that things continue to work is referred to as - -"liveness". One of the defects of ad hoc solutions to performance - -problems is the possibility that two different approaches will interact - -to prevent liveness. It is believed that the algorithms described in - -this paper are always live, and that is one of the reasons why there is - -a strong advantage in uniform use of this particular proposal, except in - -cases where it is explicitly demonstrated not to work. - - - The argument for liveness in these solutions proceeds as follows. - - 20 - - -First, the sender algorithm can only be stopped by one thing, a refusal - -of the receiver to acknowledge sent data. As long as the receiver - -continues to acknowledge data, the ratio of useable window to offered - -window will approach one, and eventually the sender must continue to - -send. However, notice that the receiver algorithm we have advocated - -involves refraining from acknowledging. Therefore, we certainly do have - -a situation where improper operation of this algorithm can prevent - -liveness. - - - What we must show is that the receiver of the data, if it chooses - -to refrain from acknowledging, will do so only for a short time, and not - -forever. The design of the algorithm described above was intended to - -achieve precisely this goal: whenever the receiver of data refrained - -from sending an acknowledgement it was required to set a timer. The - -only event that was permitted to clear that timer was the receipt of - -another segment, which essentially reset the timer, and started it going - -again. Thus, an acknowledgement will be sent as soon as no data has - -been received. This has precisely the effect desired: if the data flow - -appears to be disrupted for any reason, the receiver responds by sending - -an up-to-date acknowledgement. In fact, the receiver algorithm is - -designed to be more robust than this, for transmission of an - -acknowledgment is triggered by two events, either a cessation of data or - -a reduction in the amount of offered window to 50 percent of the actual - -value. This is the condition which will normally trigger the - -transmission of this acknowledgement. - - 21 - - - - - - APPENDIX A - - - Dynamic Calculation of Acknowledgement Delay - - - The text suggested that when setting a timer to postpone the - -sending of an acknowledgement, a fixed interval of 200 to 300 - -milliseconds would work properly in practice. This has not been - -verified over a wide variety of network delays, and clearly if there is - -a very slow net which stretches out the intersegment arrival time, a - -fixed interval will fail. In a sophisticated TCP, which is expected to - -adjust dynamically (rather than manually) to changing network - -conditions, it would be appropriate to measure this interval and respond - -dynamically. The following algorithm, which has been relegated to an - -Appendix, because it has not been tested, seems sensible. Whenever a - -segment arrives which does not have the push bit on in it, start a - -timer, which runs until the next segment arrives. Average these - -interarrival intervals, using an exponential decay smoothing function - -tuned to take into account perhaps the last ten or twenty segments that - -have come in. Occasionally, there will be a long interarrival period, - -even for a segment which is does not terminate a piece of data being - -pushed, perhaps because a window has gone to zero or some glitch in the - -sender or the network has held up the data. Therefore, examine each - -interarrival interval, and discard it from the smoothing algorithm if it - -exceeds the current estimate by some amount, perhaps a ratio of two or - -four times. By rejecting the larger intersegment arrival intervals, one - -should obtain a smoothed estimate of the interarrival of segments inside - - 22 - - -a burst. The number need not be exact, since the timer which triggers - -acknowledgement can add a fairly generous fudge factor to this without - -causing trouble with the sender's estimate of the retransmission - -interval, so long as the fudge factor is constant. - - diff --git a/ext/picotcp/RFC/rfc0814.txt b/ext/picotcp/RFC/rfc0814.txt deleted file mode 100644 index b82819e..0000000 --- a/ext/picotcp/RFC/rfc0814.txt +++ /dev/null @@ -1,763 +0,0 @@ - -RFC: 814 - - - - NAME, ADDRESSES, PORTS, AND ROUTES - - David D. Clark - MIT Laboratory for Computer Science - Computer Systems and Communications Group - July, 1982 - - - 1. Introduction - - - It has been said that the principal function of an operating system - -is to define a number of different names for the same object, so that it - -can busy itself keeping track of the relationship between all of the - -different names. Network protocols seem to have somewhat the same - -characteristic. In TCP/IP, there are several ways of referring to - -things. At the human visible interface, there are character string - -"names" to identify networks, hosts, and services. Host names are - -translated into network "addresses", 32-bit values that identify the - -network to which a host is attached, and the location of the host on - -that net. Service names are translated into a "port identifier", which - -in TCP is a 16-bit value. Finally, addresses are translated into - -"routes", which are the sequence of steps a packet must take to reach - -the specified addresses. Routes show up explicitly in the form of the - -internet routing options, and also implicitly in the address to route - -translation tables which all hosts and gateways maintain. - - - This RFC gives suggestions and guidance for the design of the - -tables and algorithms necessary to keep track of these various sorts of - -identifiers inside a host implementation of TCP/IP. - - 2 - - - 2. The Scope of the Problem - - - One of the first questions one can ask about a naming mechanism is - -how many names one can expect to encounter. In order to answer this, it - -is necessary to know something about the expected maximum size of the - -internet. Currently, the internet is fairly small. It contains no more - -than 25 active networks, and no more than a few hundred hosts. This - -makes it possible to install tables which exhaustively list all of these - -elements. However, any implementation undertaken now should be based on - -an assumption of a much larger internet. The guidelines currently - -recommended are an upper limit of about 1,000 networks. If we imagine - -an average number of 25 hosts per net, this would suggest a maximum - -number of 25,000 hosts. It is quite unclear whether this host estimate - -is high or low, but even if it is off by several factors of two, the - -resulting number is still large enough to suggest that current table - -management strategies are unacceptable. Some fresh techniques will be - -required to deal with the internet of the future. - - - 3. Names - - - As the previous section suggests, the internet will eventually have - -a sufficient number of names that a host cannot have a static table - -which provides a translation from every name to its associated address. - -There are several reasons other than sheer size why a host would not - -wish to have such a table. First, with that many names, we can expect - -names to be added and deleted at such a rate that an installer might - -spend all his time just revising the table. Second, most of the names - -will refer to addresses of machines with which nothing will ever be - - 3 - - -exchanged. In fact, there may be whole networks with which a particular - -host will never have any traffic. - - - To cope with this large and somewhat dynamic environment, the - -internet is moving from its current position in which a single name - -table is maintained by the NIC and distributed to all hosts, to a - -distributed approach in which each network (or group of networks) is - -responsible for maintaining its own names and providing a "name server" - -to translate between the names and the addresses in that network. Each - -host is assumed to store not a complete set of name-address - -translations, but only a cache of recently used names. When a name is - -provided by a user for translation to an address, the host will first - -examine its local cache, and if the name is not found there, will - -communicate with an appropriate name server to obtain the information, - -which it may then insert into its cache for future reference. - - - Unfortunately, the name server mechanism is not totally in place in - -the internet yet, so for the moment, it is necessary to continue to use - -the old strategy of maintaining a complete table of all names in every - -host. Implementors, however, should structure this table in such a way - -that it is easy to convert later to a name server approach. In - -particular, a reasonable programming strategy would be to make the name - -table accessible only through a subroutine interface, rather than by - -scattering direct references to the table all through the code. In this - -way, it will be possible, at a later date, to replace the subroutine - -with one capable of making calls on remote name servers. - - - A problem which occasionally arises in the ARPANET today is that - - 4 - - -the information in a local host table is out of date, because a host has - -moved, and a revision of the host table has not yet been installed from - -the NIC. In this case, one attempts to connect to a particular host and - -discovers an unexpected machine at the address obtained from the local - -table. If a human is directly observing the connection attempt, the - -error is usually detected immediately. However, for unattended - -operations such as the sending of queued mail, this sort of problem can - -lead to a great deal of confusion. - - - The nameserver scheme will only make this problem worse, if hosts - -cache locally the address associated with names that have been looked - -up, because the host has no way of knowing when the address has changed - -and the cache entry should be removed. To solve this problem, plans are - -currently under way to define a simple facility by which a host can - -query a foreign address to determine what name is actually associated - -with it. SMTP already defines a verification technique based on this - -approach. - - - 4. Addresses - - - The IP layer must know something about addresses. In particular, - -when a datagram is being sent out from a host, the IP layer must decide - -where to send it on the immediately connected network, based on the - -internet address. Mechanically, the IP first tests the internet address - -to see whether the network number of the recipient is the same as the - -network number of the sender. If so, the packet can be sent directly to - -the final recipient. If not, the datagram must be sent to a gateway for - -further forwarding. In this latter case, a second decision must be - - 5 - - -made, as there may be more than one gateway available on the immediately - -attached network. - - - When the internet address format was first specified, 8 bits were - -reserved to identify the network. Early implementations thus - -implemented the above algorithm by means of a table with 256 entries, - -one for each possible net, that specified the gateway of choice for that - -net, with a special case entry for those nets to which the host was - -immediately connected. Such tables were sometimes statically filled in, - -which caused confusion and malfunctions when gateways and networks moved - -(or crashed). - - - The current definition of the internet address provides three - -different options for network numbering, with the goal of allowing a - -very large number of networks to be part of the internet. Thus, it is - -no longer possible to imagine having an exhaustive table to select a - -gateway for any foreign net. Again, current implementations must use a - -strategy based on a local cache of routing information for addresses - -currently being used. - - - The recommended strategy for address to route translation is as - -follows. When the IP layer receives an outbound datagram for - -transmission, it extracts the network number from the destination - -address, and queries its local table to determine whether it knows a - -suitable gateway to which to send the datagram. If it does, the job is - -done. (But see RFC 816 on Fault Isolation and Recovery, for - -recommendations on how to deal with the possible failure of the - -gateway.) If there is no such entry in the local table, then select any - - 6 - - -accessible gateway at random, insert that as an entry in the table, and - -use it to send the packet. Either the guess will be right or wrong. If - -it is wrong, the gateway to which the packet was sent will return an - -ICMP redirect message to report that there is a better gateway to reach - -the net in question. The arrival of this redirect should cause an - -update of the local table. - - - The number of entries in the local table should be determined by - -the maximum number of active connections which this particular host can - -support at any one time. For a large time sharing system, one might - -imagine a table with 100 or more entries. For a personal computer being - -used to support a single user telnet connection, only one address to - -gateway association need be maintained at once. - - - The above strategy actually does not completely solve the problem, - -but only pushes it down one level, where the problem then arises of how - -a new host, freshly arriving on the internet, finds all of its - -accessible gateways. Intentionally, this problem is not solved within - -the internetwork architecture. The reason is that different networks - -have drastically different strategies for allowing a host to find out - -about other hosts on its immediate network. Some nets permit a - -broadcast mechanism. In this case, a host can send out a message and - -expect an answer back from all of the attached gateways. In other - -cases, where a particular network is richly provided with tools to - -support the internet, there may be a special network mechanism which a - -host can invoke to determine where the gateways are. In other cases, it - -may be necessary for an installer to manually provide the name of at - - 7 - - -least one accessible gateway. Once a host has discovered the name of - -one gateway, it can build up a table of all other available gateways, by - -keeping track of every gateway that has been reported back to it in an - -ICMP message. - - - 5. Advanced Topics in Addressing and Routing - - - The preceding discussion describes the mechanism required in a - -minimal implementation, an implementation intended only to provide - -operational service access today to the various networks that make up - -the internet. For any host which will participate in future research, - -as contrasted with service, some additional features are required. - -These features will also be helpful for service hosts if they wish to - -obtain access to some of the more exotic networks which will become part - -of the internet over the next few years. All implementors are urged to - -at least provide a structure into which these features could be later - -integrated. - - - There are several features, either already a part of the - -architecture or now under development, which are used to modify or - -expand the relationships between addresses and routes. The IP source - -route options allow a host to explicitly direct a datagram through a - -series of gateways to its foreign host. An alternative form of the ICMP - -redirect packet has been proposed, which would return information - -specific to a particular destination host, not a destination net. - -Finally, additional IP options have been proposed to identify particular - -routes within the internet that are unacceptable. The difficulty with - -implementing these new features is that the mechanisms do not lie - - 8 - - -entirely within the bounds of IP. All the mechanisms above are designed - -to apply to a particular connection, so that their use must be specified - -at the TCP level. Thus, the interface between IP and the layers above - -it must include mechanisms to allow passing this information back and - -forth, and TCP (or any other protocol at this level, such as UDP), must - -be prepared to store this information. The passing of information - -between IP and TCP is made more complicated by the fact that some of the - -information, in particular ICMP packets, may arrive at any time. The - -normal interface envisioned between TCP and IP is one across which - -packets can be sent or received. The existence of asynchronous ICMP - -messages implies that there must be an additional channel between the - -two, unrelated to the actual sending and receiving of data. (In fact, - -there are many other ICMP messages which arrive asynchronously and which - -must be passed from IP up to higher layers. See RFC 816, Fault - -Isolation and Recovery.) - - - Source routes are already in use in the internet, and many - -implementations will wish to be able to take advantage of them. The - -following sorts of usages should be permitted. First, a user, when - -initiating a TCP connection, should be able to hand a source route into - -TCP, which in turn must hand the source route to IP with every outgoing - -datagram. The user might initially obtain the source route by querying - -a different sort of name server, which would return a source route - -instead of an address, or the user may have fabricated the source route - -manually. A TCP which is listening for a connection, rather than - -attempting to open one, must be prepared to receive a datagram which - -contains a IP return route, in which case it must remember this return - -route, and use it as a source route on all returning datagrams. - - 9 - - - 6. Ports and Service Identifiers - - - The IP layer of the architecture contains the address information - -which specifies the destination host to which the datagram is being - -sent. In fact, datagrams are not intended just for particular hosts, - -but for particular agents within a host, processes or other entities - -that are the actual source and sink of the data. IP performs only a - -very simple dispatching once the datagram has arrived at the target - -host, it dispatches it to a particular protocol. It is the - -responsibility of that protocol handler, for example TCP, to finish - -dispatching the datagram to the particular connection for which it is - -destined. This next layer of dispatching is done using "port - -identifiers", which are a part of the header of the higher level - -protocol, and not the IP layer. - - - This two-layer dispatching architecture has caused a problem for - -certain implementations. In particular, some implementations have - -wished to put the IP layer within the kernel of the operating system, - -and the TCP layer as a user domain application program. Strict - -adherence to this partitioning can lead to grave performance problems, - -for the datagram must first be dispatched from the kernel to a TCP - -process, which then dispatches the datagram to its final destination - -process. The overhead of scheduling this dispatch process can severely - -limit the achievable throughput of the implementation. - - - As is discussed in RFC 817, Modularity and Efficiency in Protocol - -Implementations, this particular separation between kernel and user - -leads to other performance problems, even ignoring the issue of port - - 10 - - -level dispatching. However, there is an acceptable shortcut which can - -be taken to move the higher level dispatching function into the IP - -layer, if this makes the implementation substantially easier. - - - In principle, every higher level protocol could have a different - -dispatching algorithm. The reason for this is discussed below. - -However, for the protocols involved in the service offering being - -implemented today, TCP and UDP, the dispatching algorithm is exactly the - -same, and the port field is located in precisely the same place in the - -header. Therefore, unless one is interested in participating in further - -protocol research, there is only one higher level dispatch algorithm. - -This algorithm takes into account the internet level foreign address, - -the protocol number, and the local port and foreign port from the higher - -level protocol header. This algorithm can be implemented as a sort of - -adjunct to the IP layer implementation, as long as no other higher level - -protocols are to be implemented. (Actually, the above statement is only - -partially true, in that the UDP dispatch function is subset of the TCP - -dispatch function. UDP dispatch depends only protocol number and local - -port. However, there is an occasion within TCP when this exact same - -subset comes into play, when a process wishes to listen for a connection - -from any foreign host. Thus, the range of mechanisms necessary to - -support TCP dispatch are also sufficient to support precisely the UDP - -requirement.) - - - The decision to remove port level dispatching from IP to the higher - -level protocol has been questioned by some implementors. It has been - -argued that if all of the address structure were part of the IP layer, - - 11 - - -then IP could do all of the packet dispatching function within the host, - -which would lead to a simpler modularity. Three problems were - -identified with this. First, not all protocol implementors could agree - -on the size of the port identifier. TCP selected a fairly short port - -identifier, 16 bits, to reduce header size. Other protocols being - -designed, however, wanted a larger port identifier, perhaps 32 bits, so - -that the port identifier, if properly selected, could be considered - -probabilistically unique. Thus, constraining the port id to one - -particular IP level mechanism would prevent certain fruitful lines of - -research. Second, ports serve a special function in addition to - -datagram delivery: certain port numbers are reserved to identify - -particular services. Thus, TCP port 23 is the remote login service. If - -ports were implemented at the IP level, then the assignment of well - -known ports could not be done on a protocol basis, but would have to be - -done in a centralized manner for all of the IP architecture. Third, IP - -was designed with a very simple layering role: IP contained exactly - -those functions that the gateways must understand. If the port idea had - -been made a part of the IP layer, it would have suggested that gateways - -needed to know about ports, which is not the case. - - - There are, of course, other ways to avoid these problems. In - -particular, the "well-known port" problem can be solved by devising a - -second mechanism, distinct from port dispatching, to name well-known - -ports. Several protocols have settled on the idea of including, in the - -packet which sets up a connection to a particular service, a more - -general service descriptor, such as a character string field. These - -special packets, which are requesting connection to a particular - - 12 - - -service, are routed on arrival to a special server, sometimes called a - -"rendezvous server", which examines the service request, selects a - -random port which is to be used for this instance of the service, and - -then passes the packet along to the service itself to commence the - -interaction. - - - For the internet architecture, this strategy had the serious flaw - -that it presumed all protocols would fit into the same service paradigm: - -an initial setup phase, which might contain a certain overhead such as - -indirect routing through a rendezvous server, followed by the packets of - -the interaction itself, which would flow directly to the process - -providing the service. Unfortunately, not all high level protocols in - -internet were expected to fit this model. The best example of this is - -isolated datagram exchange using UDP. The simplest exchange in UDP is - -one process sending a single datagram to another. Especially on a local - -net, where the net related overhead is very low, this kind of simple - -single datagram interchange can be extremely efficient, with very low - -overhead in the hosts. However, since these individual packets would - -not be part of an established connection, if IP supported a strategy - -based on a rendezvous server and service descriptors, every isolated - -datagram would have to be routed indirectly in the receiving host - -through the rendezvous server, which would substantially increase the - -overhead of processing, and every datagram would have to carry the full - -service request field, which would increase the size of the packet - -header. - - - In general, if a network is intended for "virtual circuit service", - - 13 - - -or things similar to that, then using a special high overhead mechanism - -for circuit setup makes sense. However, current directions in research - -are leading away from this class of protocol, so once again the - -architecture was designed not to preclude alternative protocol - -structures. The only rational position was that the particular - -dispatching strategy used should be part of the higher level protocol - -design, not the IP layer. - - - This same argument about circuit setup mechanisms also applies to - -the design of the IP address structure. Many protocols do not transmit - -a full address field as part of every packet, but rather transmit a - -short identifier which is created as part of a circuit setup from source - -to destination. If the full address needs to be carried in only the - -first packet of a long exchange, then the overhead of carrying a very - -long address field can easily be justified. Under these circumstances, - -one can create truly extravagant address fields, which are capable of - -extending to address almost any conceivable entity. However, this - -strategy is useable only in a virtual circuit net, where the packets - -being transmitted are part of a established sequence, otherwise this - -large extravagant address must be transported on every packet. Since - -Internet explicitly rejected this restriction on the architecture, it - -was necessary to come up with an address field that was compact enough - -to be sent in every datagram, but general enough to correctly route the - -datagram through the catanet without a previous setup phase. The IP - -address of 32 bits is the compromise that results. Clearly it requires - -a substantial amount of shoehorning to address all of the interesting - -places in the universe with only 32 bits. On the other hand, had the - - 14 - - -address field become much bigger, IP would have been susceptible to - -another criticism, which is that the header had grown unworkably large. - -Again, the fundamental design decision was that the protocol be designed - -in such a way that it supported research in new and different sorts of - -protocol architectures. - - - There are some limited restrictions imposed by the IP design on the - -port mechanism selected by the higher level process. In particular, - -when a packet goes awry somewhere on the internet, the offending packet - -is returned, along with an error indication, as part of an ICMP packet. - -An ICMP packet returns only the IP layer, and the next 64 bits of the - -original datagram. Thus, any higher level protocol which wishes to sort - -out from which port a particular offending datagram came must make sure - -that the port information is contained within the first 64 bits of the - -next level header. This also means, in most cases, that it is possible - -to imagine, as part of the IP layer, a port dispatch mechanism which - -works by masking and matching on the first 64 bits of the incoming - -higher level header. - - diff --git a/ext/picotcp/RFC/rfc0816.txt b/ext/picotcp/RFC/rfc0816.txt deleted file mode 100644 index 28e01d5..0000000 --- a/ext/picotcp/RFC/rfc0816.txt +++ /dev/null @@ -1,648 +0,0 @@ - - -RFC: 816 - - - - FAULT ISOLATION AND RECOVERY - - David D. Clark - MIT Laboratory for Computer Science - Computer Systems and Communications Group - July, 1982 - - - 1. Introduction - - - Occasionally, a network or a gateway will go down, and the sequence - -of hops which the packet takes from source to destination must change. - -Fault isolation is that action which hosts and gateways collectively - -take to determine that something is wrong; fault recovery is the - -identification and selection of an alternative route which will serve to - -reconnect the source to the destination. In fact, the gateways perform - -most of the functions of fault isolation and recovery. There are, - -however, a few actions which hosts must take if they wish to provide a - -reasonable level of service. This document describes the portion of - -fault isolation and recovery which is the responsibility of the host. - - - 2. What Gateways Do - - - Gateways collectively implement an algorithm which identifies the - -best route between all pairs of networks. They do this by exchanging - -packets which contain each gateway's latest opinion about the - -operational status of its neighbor networks and gateways. Assuming that - -this algorithm is operating properly, one can expect the gateways to go - -through a period of confusion immediately after some network or gateway - - 2 - - -has failed, but one can assume that once a period of negotiation has - -passed, the gateways are equipped with a consistent and correct model of - -the connectivity of the internet. At present this period of negotiation - -may actually take several minutes, and many TCP implementations time out - -within that period, but it is a design goal of the eventual algorithm - -that the gateway should be able to reconstruct the topology quickly - -enough that a TCP connection should be able to survive a failure of the - -route. - - - 3. Host Algorithm for Fault Recovery - - - Since the gateways always attempt to have a consistent and correct - -model of the internetwork topology, the host strategy for fault recovery - -is very simple. Whenever the host feels that something is wrong, it - -asks the gateway for advice, and, assuming the advice is forthcoming, it - -believes the advice completely. The advice will be wrong only during - -the transient period of negotiation, which immediately follows an - -outage, but will otherwise be reliably correct. - - - In fact, it is never necessary for a host to explicitly ask a - -gateway for advice, because the gateway will provide it as appropriate. - -When a host sends a datagram to some distant net, the host should be - -prepared to receive back either of two advisory messages which the - -gateway may send. The ICMP "redirect" message indicates that the - -gateway to which the host sent the datagram is not longer the best - -gateway to reach the net in question. The gateway will have forwarded - -the datagram, but the host should revise its routing table to have a - -different immediate address for this net. The ICMP "destination - - 3 - - -unreachable" message indicates that as a result of an outage, it is - -currently impossible to reach the addressed net or host in any manner. - -On receipt of this message, a host can either abandon the connection - -immediately without any further retransmission, or resend slowly to see - -if the fault is corrected in reasonable time. - - - If a host could assume that these two ICMP messages would always - -arrive when something was amiss in the network, then no other action on - -the part of the host would be required in order maintain its tables in - -an optimal condition. Unfortunately, there are two circumstances under - -which the messages will not arrive properly. First, during the - -transient following a failure, error messages may arrive that do not - -correctly represent the state of the world. Thus, hosts must take an - -isolated error message with some scepticism. (This transient period is - -discussed more fully below.) Second, if the host has been sending - -datagrams to a particular gateway, and that gateway itself crashes, then - -all the other gateways in the internet will reconstruct the topology, - -but the gateway in question will still be down, and therefore cannot - -provide any advice back to the host. As long as the host continues to - -direct datagrams at this dead gateway, the datagrams will simply vanish - -off the face of the earth, and nothing will come back in return. Hosts - -must detect this failure. - - - If some gateway many hops away fails, this is not of concern to the - -host, for then the discovery of the failure is the responsibility of the - -immediate neighbor gateways, which will perform this action in a manner - -invisible to the host. The problem only arises if the very first - - 4 - - -gateway, the one to which the host is immediately sending the datagrams, - -fails. We thus identify one single task which the host must perform as - -its part of fault isolation in the internet: the host must use some - -strategy to detect that a gateway to which it is sending datagrams is - -dead. - - - Let us assume for the moment that the host implements some - -algorithm to detect failed gateways; we will return later to discuss - -what this algorithm might be. First, let us consider what the host - -should do when it has determined that a gateway is down. In fact, with - -the exception of one small problem, the action the host should take is - -extremely simple. The host should select some other gateway, and try - -sending the datagram to it. Assuming that gateway is up, this will - -either produce correct results, or some ICMP advice. Since we assume - -that, ignoring temporary periods immediately following an outage, any - -gateway is capable of giving correct advice, once the host has received - -advice from any gateway, that host is in as good a condition as it can - -hope to be. - - - There is always the unpleasant possibility that when the host tries - -a different gateway, that gateway too will be down. Therefore, whatever - -algorithm the host uses to detect a dead gateway must continuously be - -applied, as the host tries every gateway in turn that it knows about. - - - The only difficult part of this algorithm is to specify the means - -by which the host maintains the table of all of the gateways to which it - -has immediate access. Currently, the specification of the internet - -protocol does not architect any message by which a host can ask to be - - 5 - - -supplied with such a table. The reason is that different networks may - -provide very different mechanisms by which this table can be filled in. - -For example, if the net is a broadcast net, such as an ethernet or a - -ringnet, every gateway may simply broadcast such a table from time to - -time, and the host need do nothing but listen to obtain the required - -information. Alternatively, the network may provide the mechanism of - -logical addressing, by which a whole set of machines can be provided - -with a single group address, to which a request can be sent for - -assistance. Failing those two schemes, the host can build up its table - -of neighbor gateways by remembering all the gateways from which it has - -ever received a message. Finally, in certain cases, it may be necessary - -for this table, or at least the initial entries in the table, to be - -constructed manually by a manager or operator at the site. In cases - -where the network in question provides absolutely no support for this - -kind of host query, at least some manual intervention will be required - -to get started, so that the host can find out about at least one - -gateway. - - - 4. Host Algorithms for Fault Isolation - - - We now return to the question raised above. What strategy should - -the host use to detect that it is talking to a dead gateway, so that it - -can know to switch to some other gateway in the list. In fact, there are - -several algorithms which can be used. All are reasonably simple to - -implement, but they have very different implications for the overhead on - -the host, the gateway, and the network. Thus, to a certain extent, the - -algorithm picked must depend on the details of the network and of the - -host. - - 6 - - - -1. NETWORK LEVEL DETECTION - - - Many networks, particularly the Arpanet, perform precisely the - -required function internal to the network. If a host sends a datagram - -to a dead gateway on the Arpanet, the network will return a "host dead" - -message, which is precisely the information the host needs to know in - -order to switch to another gateway. Some early implementations of - -Internet on the Arpanet threw these messages away. That is an - -exceedingly poor idea. - - -2. CONTINUOUS POLLING - - - The ICMP protocol provides an echo mechanism by which a host may - -solicit a response from a gateway. A host could simply send this - -message at a reasonable rate, to assure itself continuously that the - -gateway was still up. This works, but, since the message must be sent - -fairly often to detect a fault in a reasonable time, it can imply an - -unbearable overhead on the host itself, the network, and the gateway. - -This strategy is prohibited except where a specific analysis has - -indicated that the overhead is tolerable. - - -3. TRIGGERED POLLING - - - If the use of polling could be restricted to only those times when - -something seemed to be wrong, then the overhead would be bearable. - -Provided that one can get the proper advice from one's higher level - -protocols, it is possible to implement such a strategy. For example, - -one could program the TCP level so that whenever it retransmitted a - - 7 - - -segment more than once, it sent a hint down to the IP layer which - -triggered polling. This strategy does not have excessive overhead, but - -does have the problem that the host may be somewhat slow to respond to - -an error, since only after polling has started will the host be able to - -confirm that something has gone wrong, and by then the TCP above may - -have already timed out. - - - Both forms of polling suffer from a minor flaw. Hosts as well as - -gateways respond to ICMP echo messages. Thus, polling cannot be used to - -detect the error that a foreign address thought to be a gateway is - -actually a host. Such a confusion can arise if the physical addresses - -of machines are rearranged. - - -4. TRIGGERED RESELECTION - - - There is a strategy which makes use of a hint from a higher level, - -as did the previous strategy, but which avoids polling altogether. - -Whenever a higher level complains that the service seems to be - -defective, the Internet layer can pick the next gateway from the list of - -available gateways, and switch to it. Assuming that this gateway is up, - -no real harm can come of this decision, even if it was wrong, for the - -worst that will happen is a redirect message which instructs the host to - -return to the gateway originally being used. If, on the other hand, the - -original gateway was indeed down, then this immediately provides a new - -route, so the period of time until recovery is shortened. This last - -strategy seems particularly clever, and is probably the most generally - -suitable for those cases where the network itself does not provide fault - -isolation. (Regretably, I have forgotten who suggested this idea to me. - -It is not my invention.) - - 8 - - - 5. Higher Level Fault Detection - - - The previous discussion has concentrated on fault detection and - -recovery at the IP layer. This section considers what the higher layers - -such as TCP should do. - - - TCP has a single fault recovery action; it repeatedly retransmits a - -segment until either it gets an acknowledgement or its connection timer - -expires. As discussed above, it may use retransmission as an event to - -trigger a request for fault recovery to the IP layer. In the other - -direction, information may flow up from IP, reporting such things as - -ICMP Destination Unreachable or error messages from the attached - -network. The only subtle question about TCP and faults is what TCP - -should do when such an error message arrives or its connection timer - -expires. - - - The TCP specification discusses the timer. In the description of - -the open call, the timeout is described as an optional value that the - -client of TCP may specify; if any segment remains unacknowledged for - -this period, TCP should abort the connection. The default for the - -timeout is 30 seconds. Early TCPs were often implemented with a fixed - -timeout interval, but this did not work well in practice, as the - -following discussion may suggest. - - - Clients of TCP can be divided into two classes: those running on - -immediate behalf of a human, such as Telnet, and those supporting a - -program, such as a mail sender. Humans require a sophisticated response - -to errors. Depending on exactly what went wrong, they may want to - - 9 - - -abandon the connection at once, or wait for a long time to see if things - -get better. Programs do not have this human impatience, but also lack - -the power to make complex decisions based on details of the exact error - -condition. For them, a simple timeout is reasonable. - - - Based on these considerations, at least two modes of operation are - -needed in TCP. One, for programs, abandons the connection without - -exception if the TCP timer expires. The other mode, suitable for - -people, never abandons the connection on its own initiative, but reports - -to the layer above when the timer expires. Thus, the human user can see - -error messages coming from all the relevant layers, TCP and ICMP, and - -can request TCP to abort as appropriate. This second mode requires that - -TCP be able to send an asynchronous message up to its client to report - -the timeout, and it requires that error messages arriving at lower - -layers similarly flow up through TCP. - - - At levels above TCP, fault detection is also required. Either of - -the following can happen. First, the foreign client of TCP can fail, - -even though TCP is still running, so data is still acknowledged and the - -timer never expires. Alternatively, the communication path can fail, - -without the TCP timer going off, because the local client has no data to - -send. Both of these have caused trouble. - - - Sending mail provides an example of the first case. When sending - -mail using SMTP, there is an SMTP level acknowledgement that is returned - -when a piece of mail is successfully delivered. Several early mail - -receiving programs would crash just at the point where they had received - -all of the mail text (so TCP did not detect a timeout due to outstanding - - 10 - - -unacknowledged data) but before the mail was acknowledged at the SMTP - -level. This failure would cause early mail senders to wait forever for - -the SMTP level acknowledgement. The obvious cure was to set a timer at - -the SMTP level, but the first attempt to do this did not work, for there - -was no simple way to select the timer interval. If the interval - -selected was short, it expired in normal operational when sending a - -large file to a slow host. An interval of many minutes was needed to - -prevent false timeouts, but that meant that failures were detected only - -very slowly. The current solution in several mailers is to pick a - -timeout interval proportional to the size of the message. - - - Server telnet provides an example of the other kind of failure. It - -can easily happen that the communications link can fail while there is - -no traffic flowing, perhaps because the user is thinking. Eventually, - -the user will attempt to type something, at which time he will discover - -that the connection is dead and abort it. But the host end of the - -connection, having nothing to send, will not discover anything wrong, - -and will remain waiting forever. In some systems there is no way for a - -user in a different process to destroy or take over such a hanging - -process, so there is no way to recover. - - - One solution to this would be to have the host server telnet query - -the user end now and then, to see if it is still up. (Telnet does not - -have an explicit query feature, but the host could negotiate some - -unimportant option, which should produce either agreement or - -disagreement in return.) The only problem with this is that a - -reasonable sample interval, if applied to every user on a large system, - - 11 - - -can generate an unacceptable amount of traffic and system overhead. A - -smart server telnet would use this query only when something seems - -wrong, perhaps when there had been no user activity for some time. - - - In both these cases, the general conclusion is that client level - -error detection is needed, and that the details of the mechanism are - -very dependent on the application. Application programmers must be made - -aware of the problem of failures, and must understand that error - -detection at the TCP or lower level cannot solve the whole problem for - -them. - - - 6. Knowing When to Give Up - - - It is not obvious, when error messages such as ICMP Destination - -Unreachable arrive, whether TCP should abandon the connection. The - -reason that error messages are difficult to interpret is that, as - -discussed above, after a failure of a gateway or network, there is a - -transient period during which the gateways may have incorrect - -information, so that irrelevant or incorrect error messages may - -sometimes return. An isolated ICMP Destination Unreachable may arrive - -at a host, for example, if a packet is sent during the period when the - -gateways are trying to find a new route. To abandon a TCP connection - -based on such a message arriving would be to ignore the valuable feature - -of the Internet that for many internal failures it reconstructs its - -function without any disruption of the end points. - - - But if failure messages do not imply a failure, what are they for? - -In fact, error messages serve several important purposes. First, if - - 12 - - -they arrive in response to opening a new connection, they probably are - -caused by opening the connection improperly (e.g., to a non-existent - -address) rather than by a transient network failure. Second, they - -provide valuable information, after the TCP timeout has occurred, as to - -the probable cause of the failure. Finally, certain messages, such as - -ICMP Parameter Problem, imply a possible implementation problem. In - -general, error messages give valuable information about what went wrong, - -but are not to be taken as absolutely reliable. A general alerting - -mechanism, such as the TCP timeout discussed above, provides a good - -indication that whatever is wrong is a serious condition, but without - -the advisory messages to augment the timer, there is no way for the - -client to know how to respond to the error. The combination of the - -timer and the advice from the error messages provide a reasonable set of - -facts for the client layer to have. It is important that error messages - -from all layers be passed up to the client module in a useful and - -consistent way. - - -------- diff --git a/ext/picotcp/RFC/rfc0817.txt b/ext/picotcp/RFC/rfc0817.txt deleted file mode 100644 index dcdef8a..0000000 --- a/ext/picotcp/RFC/rfc0817.txt +++ /dev/null @@ -1,1388 +0,0 @@ - -RFC: 817 - - - - MODULARITY AND EFFICIENCY IN PROTOCOL IMPLEMENTATION - - David D. Clark - MIT Laboratory for Computer Science - Computer Systems and Communications Group - July, 1982 - - - 1. Introduction - - - Many protocol implementers have made the unpleasant discovery that - -their packages do not run quite as fast as they had hoped. The blame - -for this widely observed problem has been attributed to a variety of - -causes, ranging from details in the design of the protocol to the - -underlying structure of the host operating system. This RFC will - -discuss some of the commonly encountered reasons why protocol - -implementations seem to run slowly. - - - Experience suggests that one of the most important factors in - -determining the performance of an implementation is the manner in which - -that implementation is modularized and integrated into the host - -operating system. For this reason, it is useful to discuss the question - -of how an implementation is structured at the same time that we consider - -how it will perform. In fact, this RFC will argue that modularity is - -one of the chief villains in attempting to obtain good performance, so - -that the designer is faced with a delicate and inevitable tradeoff - -between good structure and good performance. Further, the single factor - -which most strongly determines how well this conflict can be resolved is - -not the protocol but the operating system. - - 2 - - - 2. Efficiency Considerations - - - There are many aspects to efficiency. One aspect is sending data - -at minimum transmission cost, which is a critical aspect of common - -carrier communications, if not in local area network communications. - -Another aspect is sending data at a high rate, which may not be possible - -at all if the net is very slow, but which may be the one central design - -constraint when taking advantage of a local net with high raw bandwidth. - -The final consideration is doing the above with minimum expenditure of - -computer resources. This last may be necessary to achieve high speed, - -but in the case of the slow net may be important only in that the - -resources used up, for example cpu cycles, are costly or otherwise - -needed. It is worth pointing out that these different goals often - -conflict; for example it is often possible to trade off efficient use of - -the computer against efficient use of the network. Thus, there may be - -no such thing as a successful general purpose protocol implementation. - - - The simplest measure of performance is throughput, measured in bits - -per second. It is worth doing a few simple computations in order to get - -a feeling for the magnitude of the problems involved. Assume that data - -is being sent from one machine to another in packets of 576 bytes, the - -maximum generally acceptable internet packet size. Allowing for header - -overhead, this packet size permits 4288 bits in each packet. If a - -useful throughput of 10,000 bits per second is desired, then a data - -bearing packet must leave the sending host about every 430 milliseconds, - -a little over two per second. This is clearly not difficult to achieve. - -However, if one wishes to achieve 100 kilobits per second throughput, - - 3 - - -the packet must leave the host every 43 milliseconds, and to achieve one - -megabit per second, which is not at all unreasonable on a high-speed - -local net, the packets must be spaced no more than 4.3 milliseconds. - - - These latter numbers are a slightly more alarming goal for which to - -set one's sights. Many operating systems take a substantial fraction of - -a millisecond just to service an interrupt. If the protocol has been - -structured as a process, it is necessary to go through a process - -scheduling before the protocol code can even begin to run. If any piece - -of a protocol package or its data must be fetched from disk, real time - -delays of between 30 to 100 milliseconds can be expected. If the - -protocol must compete for cpu resources with other processes of the - -system, it may be necessary to wait a scheduling quantum before the - -protocol can run. Many systems have a scheduling quantum of 100 - -milliseconds or more. Considering these sorts of numbers, it becomes - -immediately clear that the protocol must be fitted into the operating - -system in a thorough and effective manner if any like reasonable - -throughput is to be achieved. - - - There is one obvious conclusion immediately suggested by even this - -simple analysis. Except in very special circumstances, when many - -packets are being processed at once, the cost of processing a packet is - -dominated by factors, such as cpu scheduling, which are independent of - -the packet size. This suggests two general rules which any - -implementation ought to obey. First, send data in large packets. - -Obviously, if processing time per packet is a constant, then throughput - -will be directly proportional to the packet size. Second, never send an - - 4 - - -unneeded packet. Unneeded packets use up just as many resources as a - -packet full of data, but perform no useful function. RFC 813, "Window - -and Acknowledgement Strategy in TCP", discusses one aspect of reducing - -the number of packets sent per useful data byte. This document will - -mention other attacks on the same problem. - - - The above analysis suggests that there are two main parts to the - -problem of achieving good protocol performance. The first has to do - -with how the protocol implementation is integrated into the host - -operating system. The second has to do with how the protocol package - -itself is organized internally. This document will consider each of - -these topics in turn. - - - 3. The Protocol vs. the Operating System - - - There are normally three reasonable ways in which to add a protocol - -to an operating system. The protocol can be in a process that is - -provided by the operating system, or it can be part of the kernel of the - -operating system itself, or it can be put in a separate communications - -processor or front end machine. This decision is strongly influenced by - -details of hardware architecture and operating system design; each of - -these three approaches has its own advantages and disadvantages. - - - The "process" is the abstraction which most operating systems use - -to provide the execution environment for user programs. A very simple - -path for implementing a protocol is to obtain a process from the - -operating system and implement the protocol to run in it. - -Superficially, this approach has a number of advantages. Since - - 5 - - -modifications to the kernel are not required, the job can be done by - -someone who is not an expert in the kernel structure. Since it is often - -impossible to find somebody who is experienced both in the structure of - -the operating system and the structure of the protocol, this path, from - -a management point of view, is often extremely appealing. Unfortunately, - -putting a protocol in a process has a number of disadvantages, related - -to both structure and performance. First, as was discussed above, - -process scheduling can be a significant source of real-time delay. - -There is not only the actual cost of going through the scheduler, but - -the problem that the operating system may not have the right sort of - -priority tools to bring the process into execution quickly whenever - -there is work to be done. - - - Structurally, the difficulty with putting a protocol in a process - -is that the protocol may be providing services, for example support of - -data streams, which are normally obtained by going to special kernel - -entry points. Depending on the generality of the operating system, it - -may be impossible to take a program which is accustomed to reading - -through a kernel entry point, and redirect it so it is reading the data - -from a process. The most extreme example of this problem occurs when - -implementing server telnet. In almost all systems, the device handler - -for the locally attached teletypes is located inside the kernel, and - -programs read and write from their teletype by making kernel calls. If - -server telnet is implemented in a process, it is then necessary to take - -the data streams provided by server telnet and somehow get them back - -down inside the kernel so that they mimic the interface provided by - -local teletypes. It is usually the case that special kernel - - 6 - - -modification is necessary to achieve this structure, which somewhat - -defeats the benefit of having removed the protocol from the kernel in - -the first place. - - - Clearly, then, there are advantages to putting the protocol package - -in the kernel. Structurally, it is reasonable to view the network as a - -device, and device drivers are traditionally contained in the kernel. - -Presumably, the problems associated with process scheduling can be - -sidesteped, at least to a certain extent, by placing the code inside the - -kernel. And it is obviously easier to make the server telnet channels - -mimic the local teletype channels if they are both realized in the same - -level in the kernel. - - - However, implementation of protocols in the kernel has its own set - -of pitfalls. First, network protocols have a characteristic which is - -shared by almost no other device: they require rather complex actions - -to be performed as a result of a timeout. The problem with this - -requirement is that the kernel often has no facility by which a program - -can be brought into execution as a result of the timer event. What is - -really needed, of course, is a special sort of process inside the - -kernel. Most systems lack this mechanism. Failing that, the only - -execution mechanism available is to run at interrupt time. - - - There are substantial drawbacks to implementing a protocol to run - -at interrupt time. First, the actions performed may be somewhat complex - -and time consuming, compared to the maximum amount of time that the - -operating system is prepared to spend servicing an interrupt. Problems - -can arise if interrupts are masked for too long. This is particularly - - 7 - - -bad when running as a result of a clock interrupt, which can imply that - -the clock interrupt is masked. Second, the environment provided by an - -interrupt handler is usually extremely primitive compared to the - -environment of a process. There are usually a variety of system - -facilities which are unavailable while running in an interrupt handler. - -The most important of these is the ability to suspend execution pending - -the arrival of some event or message. It is a cardinal rule of almost - -every known operating system that one must not invoke the scheduler - -while running in an interrupt handler. Thus, the programmer who is - -forced to implement all or part of his protocol package as an interrupt - -handler must be the best sort of expert in the operating system - -involved, and must be prepared for development sessions filled with - -obscure bugs which crash not just the protocol package but the entire - -operating system. - - - A final problem with processing at interrupt time is that the - -system scheduler has no control over the percentage of system time used - -by the protocol handler. If a large number of packets arrive, from a - -foreign host that is either malfunctioning or fast, all of the time may - -be spent in the interrupt handler, effectively killing the system. - - - There are other problems associated with putting protocols into an - -operating system kernel. The simplest problem often encountered is that - -the kernel address space is simply too small to hold the piece of code - -in question. This is a rather artificial sort of problem, but it is a - -severe problem none the less in many machines. It is an appallingly - -unpleasant experience to do an implementation with the knowledge that - - 8 - - -for every byte of new feature put in one must find some other byte of - -old feature to throw out. It is hopeless to expect an effective and - -general implementation under this kind of constraint. Another problem - -is that the protocol package, once it is thoroughly entwined in the - -operating system, may need to be redone every time the operating system - -changes. If the protocol and the operating system are not maintained by - -the same group, this makes maintenance of the protocol package a - -perpetual headache. - - - The third option for protocol implementation is to take the - -protocol package and move it outside the machine entirely, on to a - -separate processor dedicated to this kind of task. Such a machine is - -often described as a communications processor or a front-end processor. - -There are several advantages to this approach. First, the operating - -system on the communications processor can be tailored for precisely - -this kind of task. This makes the job of implementation much easier. - -Second, one does not need to redo the task for every machine to which - -the protocol is to be added. It may be possible to reuse the same - -front-end machine on different host computers. Since the task need not - -be done as many times, one might hope that more attention could be paid - -to doing it right. Given a careful implementation in an environment - -which is optimized for this kind of task, the resulting package should - -turn out to be very efficient. Unfortunately, there are also problems - -with this approach. There is, of course, a financial problem associated - -with buying an additional computer. In many cases, this is not a - -problem at all since the cost is negligible compared to what the - -programmer would cost to do the job in the mainframe itself. More - - 9 - - -fundamentally, the communications processor approach does not completely - -sidestep any of the problems raised above. The reason is that the - -communications processor, since it is a separate machine, must be - -attached to the mainframe by some mechanism. Whatever that mechanism, - -code is required in the mainframe to deal with it. It can be argued - -that the program to deal with the communications processor is simpler - -than the program to implement the entire protocol package. Even if that - -is so, the communications processor interface package is still a - -protocol in nature, with all of the same structural problems. Thus, all - -of the issues raised above must still be faced. In addition to those - -problems, there are some other, more subtle problems associated with an - -outboard implementation of a protocol. We will return to these problems - -later. - - - There is a way of attaching a communications processor to a - -mainframe host which sidesteps all of the mainframe implementation - -problems, which is to use some preexisting interface on the host machine - -as the port by which a communications processor is attached. This - -strategy is often used as a last stage of desperation when the software - -on the host computer is so intractable that it cannot be changed in any - -way. Unfortunately, it is almost inevitably the case that all of the - -available interfaces are totally unsuitable for this purpose, so the - -result is unsatisfactory at best. The most common way in which this - -form of attachment occurs is when a network connection is being used to - -mimic local teletypes. In this case, the front-end processor can be - -attached to the mainframe by simply providing a number of wires out of - -the front-end processor, each corresponding to a connection, which are - - 10 - - -plugged into teletype ports on the mainframe computer. (Because of the - -appearance of the physical configuration which results from this - -arrangement, Michael Padlipsky has described this as the "milking - -machine" approach to computer networking.) This strategy solves the - -immediate problem of providing remote access to a host, but it is - -extremely inflexible. The channels being provided to the host are - -restricted by the host software to one purpose only, remote login. It - -is impossible to use them for any other purpose, such as file transfer - -or sending mail, so the host is integrated into the network environment - -in an extremely limited and inflexible manner. If this is the best that - -can be done, then it should be tolerated. Otherwise, implementors - -should be strongly encouraged to take a more flexible approach. - - - 4. Protocol Layering - - - The previous discussion suggested that there was a decision to be - -made as to where a protocol ought to be implemented. In fact, the - -decision is much more complicated than that, for the goal is not to - -implement a single protocol, but to implement a whole family of protocol - -layers, starting with a device driver or local network driver at the - -bottom, then IP and TCP, and eventually reaching the application - -specific protocol, such as Telnet, FTP and SMTP on the top. Clearly, - -the bottommost of these layers is somewhere within the kernel, since the - -physical device driver for the net is almost inevitably located there. - -Equally clearly, the top layers of this package, which provide the user - -his ability to perform the remote login function or to send mail, are - -not entirely contained within the kernel. Thus, the question is not - - 11 - - -whether the protocol family shall be inside or outside the kernel, but - -how it shall be sliced in two between that part inside and that part - -outside. - - - Since protocols come nicely layered, an obvious proposal is that - -one of the layer interfaces should be the point at which the inside and - -outside components are sliced apart. Most systems have been implemented - -in this way, and many have been made to work quite effectively. One - -obvious place to slice is at the upper interface of TCP. Since TCP - -provides a bidirectional byte stream, which is somewhat similar to the - -I/O facility provided by most operating systems, it is possible to make - -the interface to TCP almost mimic the interface to other existing - -devices. Except in the matter of opening a connection, and dealing with - -peculiar failures, the software using TCP need not know that it is a - -network connection, rather than a local I/O stream that is providing the - -communications function. This approach does put TCP inside the kernel, - -which raises all the problems addressed above. It also raises the - -problem that the interface to the IP layer can, if the programmer is not - -careful, become excessively buried inside the kernel. It must be - -remembered that things other than TCP are expected to run on top of IP. - -The IP interface must be made accessible, even if TCP sits on top of it - -inside the kernel. - - - Another obvious place to slice is above Telnet. The advantage of - -slicing above Telnet is that it solves the problem of having remote - -login channels emulate local teletype channels. The disadvantage of - -putting Telnet into the kernel is that the amount of code which has now - - 12 - - -been included there is getting remarkably large. In some early - -implementations, the size of the network package, when one includes - -protocols at the level of Telnet, rivals the size of the rest of the - -supervisor. This leads to vague feelings that all is not right. - - - Any attempt to slice through a lower layer boundary, for example - -between internet and TCP, reveals one fundamental problem. The TCP - -layer, as well as the IP layer, performs a demultiplexing function on - -incoming datagrams. Until the TCP header has been examined, it is not - -possible to know for which user the packet is ultimately destined. - -Therefore, if TCP, as a whole, is moved outside the kernel, it is - -necessary to create one separate process called the TCP process, which - -performs the TCP multiplexing function, and probably all of the rest of - -TCP processing as well. This means that incoming data destined for a - -user process involves not just a scheduling of the user process, but - -scheduling the TCP process first. - - - This suggests an alternative structuring strategy which slices - -through the protocols, not along an established layer boundary, but - -along a functional boundary having to do with demultiplexing. In this - -approach, certain parts of IP and certain parts of TCP are placed in the - -kernel. The amount of code placed there is sufficient so that when an - -incoming datagram arrives, it is possible to know for which process that - -datagram is ultimately destined. The datagram is then routed directly - -to the final process, where additional IP and TCP processing is - -performed on it. This removes from the kernel any requirement for timer - -based actions, since they can be done by the process provided by the - - 13 - - -user. This structure has the additional advantage of reducing the - -amount of code required in the kernel, so that it is suitable for - -systems where kernel space is at a premium. The RFC 814, titled "Names, - -Addresses, Ports, and Routes," discusses this rather orthogonal slicing - -strategy in more detail. - - - A related discussion of protocol layering and multiplexing can be - -found in Cohen and Postel [1]. - - - 5. Breaking Down the Barriers - - - In fact, the implementor should be sensitive to the possibility of - -even more peculiar slicing strategies in dividing up the various - -protocol layers between the kernel and the one or more user processes. - -The result of the strategy proposed above was that part of TCP should - -execute in the process of the user. In other words, instead of having - -one TCP process for the system, there is one TCP process per connection. - -Given this architecture, it is not longer necessary to imagine that all - -of the TCPs are identical. One TCP could be optimized for high - -throughput applications, such as file transfer. Another TCP could be - -optimized for small low delay applications such as Telnet. In fact, it - -would be possible to produce a TCP which was somewhat integrated with - -the Telnet or FTP on top of it. Such an integration is extremely - -important, for it can lead to a kind of efficiency which more - -traditional structures are incapable of producing. Earlier, this paper - -pointed out that one of the important rules to achieving efficiency was - -to send the minimum number of packets for a given amount of data. The - -idea of protocol layering interacts very strongly (and poorly) with this - - 14 - - -goal, because independent layers have independent ideas about when - -packets should be sent, and unless these layers can somehow be brought - -into cooperation, additional packets will flow. The best example of - -this is the operation of server telnet in a character at a time remote - -echo mode on top of TCP. When a packet containing a character arrives - -at a server host, each layer has a different response to that packet. - -TCP has an obligation to acknowledge the packet. Either server telnet - -or the application layer above has an obligation to echo the character - -received in the packet. If the character is a Telnet control sequence, - -then Telnet has additional actions which it must perform in response to - -the packet. The result of this, in most implementations, is that - -several packets are sent back in response to the one arriving packet. - -Combining all of these return messages into one packet is important for - -several reasons. First, of course, it reduces the number of packets - -being sent over the net, which directly reduces the charges incurred for - -many common carrier tariff structures. Second, it reduces the number of - -scheduling actions which will occur inside both hosts, which, as was - -discussed above, is extremely important in improving throughput. - - - The way to achieve this goal of packet sharing is to break down the - -barrier between the layers of the protocols, in a very restrained and - -careful manner, so that a limited amount of information can leak across - -the barrier to enable one layer to optimize its behavior with respect to - -the desires of the layers above and below it. For example, it would - -represent an improvement if TCP, when it received a packet, could ask - -the layer above whether or not it would be worth pausing for a few - -milliseconds before sending an acknowledgement in order to see if the - - 15 - - -upper layer would have any outgoing data to send. Dallying before - -sending the acknowledgement produces precisely the right sort of - -optimization if the client of TCP is server Telnet. However, dallying - -before sending an acknowledgement is absolutely unacceptable if TCP is - -being used for file transfer, for in file transfer there is almost never - -data flowing in the reverse direction, and the delay in sending the - -acknowledgement probably translates directly into a delay in obtaining - -the next packets. Thus, TCP must know a little about the layers above - -it to adjust its performance as needed. - - - It would be possible to imagine a general purpose TCP which was - -equipped with all sorts of special mechanisms by which it would query - -the layer above and modify its behavior accordingly. In the structures - -suggested above, in which there is not one but several TCPs, the TCP can - -simply be modified so that it produces the correct behavior as a matter - -of course. This structure has the disadvantage that there will be - -several implementations of TCP existing on a single machine, which can - -mean more maintenance headaches if a problem is found where TCP needs to - -be changed. However, it is probably the case that each of the TCPs will - -be substantially simpler than the general purpose TCP which would - -otherwise have been built. There are some experimental projects - -currently under way which suggest that this approach may make designing - -of a TCP, or almost any other layer, substantially easier, so that the - -total effort involved in bringing up a complete package is actually less - -if this approach is followed. This approach is by no means generally - -accepted, but deserves some consideration. - - 16 - - - The general conclusion to be drawn from this sort of consideration - -is that a layer boundary has both a benefit and a penalty. A visible - -layer boundary, with a well specified interface, provides a form of - -isolation between two layers which allows one to be changed with the - -confidence that the other one will not stop working as a result. - -However, a firm layer boundary almost inevitably leads to inefficient - -operation. This can easily be seen by analogy with other aspects of - -operating systems. Consider, for example, file systems. A typical - -operating system provides a file system, which is a highly abstracted - -representation of a disk. The interface is highly formalized, and - -presumed to be highly stable. This makes it very easy for naive users - -to have access to disks without having to write a great deal of - -software. The existence of a file system is clearly beneficial. On the - -other hand, it is clear that the restricted interface to a file system - -almost inevitably leads to inefficiency. If the interface is organized - -as a sequential read and write of bytes, then there will be people who - -wish to do high throughput transfers who cannot achieve their goal. If - -the interface is a virtual memory interface, then other users will - -regret the necessity of building a byte stream interface on top of the - -memory mapped file. The most objectionable inefficiency results when a - -highly sophisticated package, such as a data base management package, - -must be built on top of an existing operating system. Almost - -inevitably, the implementors of the database system attempt to reject - -the file system and obtain direct access to the disks. They have - -sacrificed modularity for efficiency. - - - The same conflict appears in networking, in a rather extreme form. - - 17 - - -The concept of a protocol is still unknown and frightening to most naive - -programmers. The idea that they might have to implement a protocol, or - -even part of a protocol, as part of some application package, is a - -dreadful thought. And thus there is great pressure to hide the function - -of the net behind a very hard barrier. On the other hand, the kind of - -inefficiency which results from this is a particularly undesirable sort - -of inefficiency, for it shows up, among other things, in increasing the - -cost of the communications resource used up to achieve the application - -goal. In cases where one must pay for one's communications costs, they - -usually turn out to be the dominant cost within the system. Thus, doing - -an excessively good job of packaging up the protocols in an inflexible - -manner has a direct impact on increasing the cost of the critical - -resource within the system. This is a dilemma which will probably only - -be solved when programmers become somewhat less alarmed about protocols, - -so that they are willing to weave a certain amount of protocol structure - -into their application program, much as application programs today weave - -parts of database management systems into the structure of their - -application program. - - - An extreme example of putting the protocol package behind a firm - -layer boundary occurs when the protocol package is relegated to a front- - -end processor. In this case the interface to the protocol is some other - -protocol. It is difficult to imagine how to build close cooperation - -between layers when they are that far separated. Realistically, one of - -the prices which must be associated with an implementation so physically - -modularized is that the performance will suffer as a result. Of course, - -a separate processor for protocols could be very closely integrated into - - 18 - - -the mainframe architecture, with interprocessor co-ordination signals, - -shared memory, and similar features. Such a physical modularity might - -work very well, but there is little documented experience with this - -closely coupled architecture for protocol support. - - - 6. Efficiency of Protocol Processing - - - To this point, this document has considered how a protocol package - -should be broken into modules, and how those modules should be - -distributed between free standing machines, the operating system kernel, - -and one or more user processes. It is now time to consider the other - -half of the efficiency question, which is what can be done to speed the - -execution of those programs that actually implement the protocols. We - -will make some specific observations about TCP and IP, and then conclude - -with a few generalities. - - - IP is a simple protocol, especially with respect to the processing - -of normal packets, so it should be easy to get it to perform - -efficiently. The only area of any complexity related to actual packet - -processing has to do with fragmentation and reassembly. The reader is - -referred to RFC 815, titled "IP Datagram Reassembly Algorithms", for - -specific consideration of this point. - - - Most costs in the IP layer come from table look up functions, as - -opposed to packet processing functions. An outgoing packet requires two - -translation functions to be performed. The internet address must be - -translated to a target gateway, and a gateway address must be translated - -to a local network number (if the host is attached to more than one - - 19 - - -network). It is easy to build a simple implementation of these table - -look up functions that in fact performs very poorly. The programmer - -should keep in mind that there may be as many as a thousand network - -numbers in a typical configuration. Linear searching of a thousand - -entry table on every packet is extremely unsuitable. In fact, it may be - -worth asking TCP to cache a hint for each connection, which can be - -handed down to IP each time a packet is sent, to try to avoid the - -overhead of a table look up. - - - TCP is a more complex protocol, and presents many more - -opportunities for getting things wrong. There is one area which is - -generally accepted as causing noticeable and substantial overhead as - -part of TCP processing. This is computation of the checksum. It would - -be nice if this cost could be avoided somehow, but the idea of an end- - -to-end checksum is absolutely central to the functioning of TCP. No - -host implementor should think of omitting the validation of a checksum - -on incoming data. - - - Various clever tricks have been used to try to minimize the cost of - -computing the checksum. If it is possible to add additional microcoded - -instructions to the machine, a checksum instruction is the most obvious - -candidate. Since computing the checksum involves picking up every byte - -of the segment and examining it, it is possible to combine the operation - -of computing the checksum with the operation of copying the segment from - -one location to another. Since a number of data copies are probably - -already required as part of the processing structure, this kind of - -sharing might conceivably pay off if it didn't cause too much trouble to - - 20 - - -the modularity of the program. Finally, computation of the checksum - -seems to be one place where careful attention to the details of the - -algorithm used can make a drastic difference in the throughput of the - -program. The Multics system provides one of the best case studies of - -this, since Multics is about as poorly organized to perform this - -function as any machine implementing TCP. Multics is a 36-bit word - -machine, with four 9-bit bytes per word. The eight-bit bytes of a TCP - -segment are laid down packed in memory, ignoring word boundaries. This - -means that when it is necessary to pick up the data as a set of 16-bit - -units for the purpose of adding them to compute checksums, horrible - -masking and shifting is required for each 16-bit value. An early - -version of a program using this strategy required 6 milliseconds to - -checksum a 576-byte segment. Obviously, at this point, checksum - -computation was becoming the central bottleneck to throughput. A more - -careful recoding of this algorithm reduced the checksum processing time - -to less than one millisecond. The strategy used was extremely dirty. - -It involved adding up carefully selected words of the area in which the - -data lay, knowing that for those particular words, the 16-bit values - -were properly aligned inside the words. Only after the addition had - -been done were the various sums shifted, and finally added to produce - -the eventual checksum. This kind of highly specialized programming is - -probably not acceptable if used everywhere within an operating system. - -It is clearly appropriate for one highly localized function which can be - -clearly identified as an extreme performance bottleneck. - - - Another area of TCP processing which may cause performance problems - -is the overhead of examining all of the possible flags and options which - - 21 - - -occur in each incoming packet. One paper, by Bunch and Day [2], asserts - -that the overhead of packet header processing is actually an important - -limiting factor in throughput computation. Not all measurement - -experiments have tended to support this result. To whatever extent it - -is true, however, there is an obvious strategy which the implementor - -ought to use in designing his program. He should build his program to - -optimize the expected case. It is easy, especially when first designing - -a program, to pay equal attention to all of the possible outcomes of - -every test. In practice, however, few of these will ever happen. A TCP - -should be built on the assumption that the next packet to arrive will - -have absolutely nothing special about it, and will be the next one - -expected in the sequence space. One or two tests are sufficient to - -determine that the expected set of control flags are on. (The ACK flag - -should be on; the Push flag may or may not be on. No other flags should - -be on.) One test is sufficient to determine that the sequence number of - -the incoming packet is one greater than the last sequence number - -received. In almost every case, that will be the actual result. Again, - -using the Multics system as an example, failure to optimize the case of - -receiving the expected sequence number had a detectable effect on the - -performance of the system. The particular problem arose when a number - -of packets arrived at once. TCP attempted to process all of these - -packets before awaking the user. As a result, by the time the last - -packet arrived, there was a threaded list of packets which had several - -items on it. When a new packet arrived, the list was searched to find - -the location into which the packet should be inserted. Obviously, the - -list should be searched from highest sequence number to lowest sequence - - 22 - - -number, because one is expecting to receive a packet which comes after - -those already received. By mistake, the list was searched from front to - -back, starting with the packets with the lowest sequence number. The - -amount of time spent searching this list backwards was easily detectable - -in the metering measurements. - - - Other data structures can be organized to optimize the action which - -is normally taken on them. For example, the retransmission queue is - -very seldom actually used for retransmission, so it should not be - -organized to optimize that action. In fact, it should be organized to - -optimized the discarding of things from it when the acknowledgement - -arrives. In many cases, the easiest way to do this is not to save the - -packet at all, but to reconstruct it only if it needs to be - -retransmitted, starting from the data as it was originally buffered by - -the user. - - - There is another generality, at least as important as optimizing - -the common case, which is to avoid copying data any more times than - -necessary. One more result from the Multics TCP may prove enlightening - -here. Multics takes between two and three milliseconds within the TCP - -layer to process an incoming packet, depending on its size. For a 576- - -byte packet, the three milliseconds is used up approximately as follows. - -One millisecond is used computing the checksum. Six hundred - -microseconds is spent copying the data. (The data is copied twice, at - -.3 milliseconds a copy.) One of those copy operations could correctly - -be included as part of the checksum cost, since it is done to get the - -data on a known word boundary to optimize the checksum algorithm. - - 23 - - -However, the copy also performs another necessary transfer at the same - -time. Header processing and packet resequencing takes .7 milliseconds. - -The rest of the time is used in miscellaneous processing, such as - -removing packets from the retransmission queue which are acknowledged by - -this packet. Data copying is the second most expensive single operation - -after data checksuming. Some implementations, often because of an - -excessively layered modularity, end up copying the data around a great - -deal. Other implementations end up copying the data because there is no - -shared memory between processes, and the data must be moved from process - -to process via a kernel operation. Unless the amount of this activity - -is kept strictly under control, it will quickly become the major - -performance bottleneck. - - - 7. Conclusions - - - This document has addressed two aspects of obtaining performance - -from a protocol implementation, the way in which the protocol is layered - -and integrated into the operating system, and the way in which the - -detailed handling of the packet is optimized. It would be nice if one - -or the other of these costs would completely dominate, so that all of - -one's attention could be concentrated there. Regrettably, this is not - -so. Depending on the particular sort of traffic one is getting, for - -example, whether Telnet one-byte packets or file transfer maximum size - -packets at maximum speed, one can expect to see one or the other cost - -being the major bottleneck to throughput. Most implementors who have - -studied their programs in an attempt to find out where the time was - -going have reached the unsatisfactory conclusion that it is going - - 24 - - -equally to all parts of their program. With the possible exception of - -checksum processing, very few people have ever found that their - -performance problems were due to a single, horrible bottleneck which - -they could fix by a single stroke of inventive programming. Rather, the - -performance was something which was improved by painstaking tuning of - -the entire program. - - - Most discussions of protocols begin by introducing the concept of - -layering, which tends to suggest that layering is a fundamentally - -wonderful idea which should be a part of every consideration of - -protocols. In fact, layering is a mixed blessing. Clearly, a layer - -interface is necessary whenever more than one client of a particular - -layer is to be allowed to use that same layer. But an interface, - -precisely because it is fixed, inevitably leads to a lack of complete - -understanding as to what one layer wishes to obtain from another. This - -has to lead to inefficiency. Furthermore, layering is a potential snare - -in that one is tempted to think that a layer boundary, which was an - -artifact of the specification procedure, is in fact the proper boundary - -to use in modularizing the implementation. Again, in certain cases, an - -architected layer must correspond to an implemented layer, precisely so - -that several clients can have access to that layer in a reasonably - -straightforward manner. In other cases, cunning rearrangement of the - -implemented module boundaries to match with various functions, such as - -the demultiplexing of incoming packets, or the sending of asynchronous - -outgoing packets, can lead to unexpected performance improvements - -compared to more traditional implementation strategies. Finally, good - -performance is something which is difficult to retrofit onto an existing - - 25 - - -program. Since performance is influenced, not just by the fine detail, - -but by the gross structure, it is sometimes the case that in order to - -obtain a substantial performance improvement, it is necessary to - -completely redo the program from the bottom up. This is a great - -disappointment to programmers, especially those doing a protocol - -implementation for the first time. Programmers who are somewhat - -inexperienced and unfamiliar with protocols are sufficiently concerned - -with getting their program logically correct that they do not have the - -capacity to think at the same time about the performance of the - -structure they are building. Only after they have achieved a logically - -correct program do they discover that they have done so in a way which - -has precluded real performance. Clearly, it is more difficult to design - -a program thinking from the start about both logical correctness and - -performance. With time, as implementors as a group learn more about the - -appropriate structures to use for building protocols, it will be - -possible to proceed with an implementation project having more - -confidence that the structure is rational, that the program will work, - -and that the program will work well. Those of us now implementing - -protocols have the privilege of being on the forefront of this learning - -process. It should be no surprise that our programs sometimes suffer - -from the uncertainty we bring to bear on them. - - 26 - - -Citations - - - [1] Cohen and Postel, "On Protocol Multiplexing", Sixth Data - -Communications Symposium, ACM/IEEE, November 1979. - - - [2] Bunch and Day, "Control Structure Overhead in TCP", Trends and - -Applications: Computer Networking, NBS Symposium, May 1980. - - diff --git a/ext/picotcp/RFC/rfc0826.txt b/ext/picotcp/RFC/rfc0826.txt deleted file mode 100644 index 8d5aae2..0000000 --- a/ext/picotcp/RFC/rfc0826.txt +++ /dev/null @@ -1,470 +0,0 @@ -Network Working Group David C. Plummer -Request For Comments: 826 (DCP@MIT-MC) - November 1982 - - - An Ethernet Address Resolution Protocol - -- or -- - Converting Network Protocol Addresses - to 48.bit Ethernet Address - for Transmission on - Ethernet Hardware - - - - - - Abstract - -The implementation of protocol P on a sending host S decides, -through protocol P's routing mechanism, that it wants to transmit -to a target host T located some place on a connected piece of -10Mbit Ethernet cable. To actually transmit the Ethernet packet -a 48.bit Ethernet address must be generated. The addresses of -hosts within protocol P are not always compatible with the -corresponding Ethernet address (being different lengths or -values). Presented here is a protocol that allows dynamic -distribution of the information needed to build tables to -translate an address A in protocol P's address space into a -48.bit Ethernet address. - -Generalizations have been made which allow the protocol to be -used for non-10Mbit Ethernet hardware. Some packet radio -networks are examples of such hardware. - --------------------------------------------------------------------- - -The protocol proposed here is the result of a great deal of -discussion with several other people, most notably J. Noel -Chiappa, Yogen Dalal, and James E. Kulp, and helpful comments -from David Moon. - - - - -[The purpose of this RFC is to present a method of Converting -Protocol Addresses (e.g., IP addresses) to Local Network -Addresses (e.g., Ethernet addresses). This is a issue of general -concern in the ARPA Internet community at this time. The -method proposed here is presented for your consideration and -comment. This is not the specification of a Internet Standard.] - -Notes: ------- - -This protocol was originally designed for the DEC/Intel/Xerox -10Mbit Ethernet. It has been generalized to allow it to be used -for other types of networks. Much of the discussion will be -directed toward the 10Mbit Ethernet. Generalizations, where -applicable, will follow the Ethernet-specific discussion. - -DOD Internet Protocol will be referred to as Internet. - -Numbers here are in the Ethernet standard, which is high byte -first. This is the opposite of the byte addressing of machines -such as PDP-11s and VAXes. Therefore, special care must be taken -with the opcode field (ar$op) described below. - -An agreed upon authority is needed to manage hardware name space -values (see below). Until an official authority exists, requests -should be submitted to - David C. Plummer - Symbolics, Inc. - 243 Vassar Street - Cambridge, Massachusetts 02139 -Alternatively, network mail can be sent to DCP@MIT-MC. - -The Problem: ------------- - -The world is a jungle in general, and the networking game -contributes many animals. At nearly every layer of a network -architecture there are several potential protocols that could be -used. For example, at a high level, there is TELNET and SUPDUP -for remote login. Somewhere below that there is a reliable byte -stream protocol, which might be CHAOS protocol, DOD TCP, Xerox -BSP or DECnet. Even closer to the hardware is the logical -transport layer, which might be CHAOS, DOD Internet, Xerox PUP, -or DECnet. The 10Mbit Ethernet allows all of these protocols -(and more) to coexist on a single cable by means of a type field -in the Ethernet packet header. However, the 10Mbit Ethernet -requires 48.bit addresses on the physical cable, yet most -protocol addresses are not 48.bits long, nor do they necessarily -have any relationship to the 48.bit Ethernet address of the -hardware. For example, CHAOS addresses are 16.bits, DOD Internet -addresses are 32.bits, and Xerox PUP addresses are 8.bits. A -protocol is needed to dynamically distribute the correspondences -between a pair and a 48.bit Ethernet address. - -Motivation: ------------ - -Use of the 10Mbit Ethernet is increasing as more manufacturers -supply interfaces that conform to the specification published by -DEC, Intel and Xerox. With this increasing availability, more -and more software is being written for these interfaces. There -are two alternatives: (1) Every implementor invents his/her own -method to do some form of address resolution, or (2) every -implementor uses a standard so that his/her code can be -distributed to other systems without need for modification. This -proposal attempts to set the standard. - -Definitions: ------------- - -Define the following for referring to the values put in the TYPE -field of the Ethernet packet header: - ether_type$XEROX_PUP, - ether_type$DOD_INTERNET, - ether_type$CHAOS, -and a new one: - ether_type$ADDRESS_RESOLUTION. -Also define the following values (to be discussed later): - ares_op$REQUEST (= 1, high byte transmitted first) and - ares_op$REPLY (= 2), -and - ares_hrd$Ethernet (= 1). - -Packet format: --------------- - -To communicate mappings from pairs to 48.bit -Ethernet addresses, a packet format that embodies the Address -Resolution protocol is needed. The format of the packet follows. - - Ethernet transmission layer (not necessarily accessible to - the user): - 48.bit: Ethernet address of destination - 48.bit: Ethernet address of sender - 16.bit: Protocol type = ether_type$ADDRESS_RESOLUTION - Ethernet packet data: - 16.bit: (ar$hrd) Hardware address space (e.g., Ethernet, - Packet Radio Net.) - 16.bit: (ar$pro) Protocol address space. For Ethernet - hardware, this is from the set of type - fields ether_typ$. - 8.bit: (ar$hln) byte length of each hardware address - 8.bit: (ar$pln) byte length of each protocol address - 16.bit: (ar$op) opcode (ares_op$REQUEST | ares_op$REPLY) - nbytes: (ar$sha) Hardware address of sender of this - packet, n from the ar$hln field. - mbytes: (ar$spa) Protocol address of sender of this - packet, m from the ar$pln field. - nbytes: (ar$tha) Hardware address of target of this - packet (if known). - mbytes: (ar$tpa) Protocol address of target. - - -Packet Generation: ------------------- - -As a packet is sent down through the network layers, routing -determines the protocol address of the next hop for the packet -and on which piece of hardware it expects to find the station -with the immediate target protocol address. In the case of the -10Mbit Ethernet, address resolution is needed and some lower -layer (probably the hardware driver) must consult the Address -Resolution module (perhaps implemented in the Ethernet support -module) to convert the -pair to a 48.bit Ethernet address. The Address Resolution module -tries to find this pair in a table. If it finds the pair, it -gives the corresponding 48.bit Ethernet address back to the -caller (hardware driver) which then transmits the packet. If it -does not, it probably informs the caller that it is throwing the -packet away (on the assumption the packet will be retransmitted -by a higher network layer), and generates an Ethernet packet with -a type field of ether_type$ADDRESS_RESOLUTION. The Address -Resolution module then sets the ar$hrd field to -ares_hrd$Ethernet, ar$pro to the protocol type that is being -resolved, ar$hln to 6 (the number of bytes in a 48.bit Ethernet -address), ar$pln to the length of an address in that protocol, -ar$op to ares_op$REQUEST, ar$sha with the 48.bit ethernet address -of itself, ar$spa with the protocol address of itself, and ar$tpa -with the protocol address of the machine that is trying to be -accessed. It does not set ar$tha to anything in particular, -because it is this value that it is trying to determine. It -could set ar$tha to the broadcast address for the hardware (all -ones in the case of the 10Mbit Ethernet) if that makes it -convenient for some aspect of the implementation. It then causes -this packet to be broadcast to all stations on the Ethernet cable -originally determined by the routing mechanism. - - - -Packet Reception: ------------------ - -When an address resolution packet is received, the receiving -Ethernet module gives the packet to the Address Resolution module -which goes through an algorithm similar to the following. -Negative conditionals indicate an end of processing and a -discarding of the packet. - -?Do I have the hardware type in ar$hrd? -Yes: (almost definitely) - [optionally check the hardware length ar$hln] - ?Do I speak the protocol in ar$pro? - Yes: - [optionally check the protocol length ar$pln] - Merge_flag := false - If the pair is - already in my translation table, update the sender - hardware address field of the entry with the new - information in the packet and set Merge_flag to true. - ?Am I the target protocol address? - Yes: - If Merge_flag is false, add the triplet to - the translation table. - ?Is the opcode ares_op$REQUEST? (NOW look at the opcode!!) - Yes: - Swap hardware and protocol fields, putting the local - hardware and protocol addresses in the sender fields. - Set the ar$op field to ares_op$REPLY - Send the packet to the (new) target hardware address on - the same hardware on which the request was received. - -Notice that the triplet is merged into the table before the -opcode is looked at. This is on the assumption that communcation -is bidirectional; if A has some reason to talk to B, then B will -probably have some reason to talk to A. Notice also that if an -entry already exists for the pair, then the new hardware address supersedes the old -one. Related Issues gives some motivation for this. - -Generalization: The ar$hrd and ar$hln fields allow this protocol -and packet format to be used for non-10Mbit Ethernets. For the -10Mbit Ethernet takes on the value <1, 6>. For -other hardware networks, the ar$pro field may no longer -correspond to the Ethernet type field, but it should be -associated with the protocol whose address resolution is being -sought. - - -Why is it done this way?? -------------------------- - -Periodic broadcasting is definitely not desired. Imagine 100 -workstations on a single Ethernet, each broadcasting address -resolution information once per 10 minutes (as one possible set -of parameters). This is one packet every 6 seconds. This is -almost reasonable, but what use is it? The workstations aren't -generally going to be talking to each other (and therefore have -100 useless entries in a table); they will be mainly talking to a -mainframe, file server or bridge, but only to a small number of -other workstations (for interactive conversations, for example). -The protocol described in this paper distributes information as -it is needed, and only once (probably) per boot of a machine. - -This format does not allow for more than one resolution to be -done in the same packet. This is for simplicity. If things were -multiplexed the packet format would be considerably harder to -digest, and much of the information could be gratuitous. Think -of a bridge that talks four protocols telling a workstation all -four protocol addresses, three of which the workstation will -probably never use. - -This format allows the packet buffer to be reused if a reply is -generated; a reply has the same length as a request, and several -of the fields are the same. - -The value of the hardware field (ar$hrd) is taken from a list for -this purpose. Currently the only defined value is for the 10Mbit -Ethernet (ares_hrd$Ethernet = 1). There has been talk of using -this protocol for Packet Radio Networks as well, and this will -require another value as will other future hardware mediums that -wish to use this protocol. - -For the 10Mbit Ethernet, the value in the protocol field (ar$pro) -is taken from the set ether_type$. This is a natural reuse of -the assigned protocol types. Combining this with the opcode -(ar$op) would effectively halve the number of protocols that can -be resolved under this protocol and would make a monitor/debugger -more complex (see Network Monitoring and Debugging below). It is -hoped that we will never see 32768 protocols, but Murphy made -some laws which don't allow us to make this assumption. - -In theory, the length fields (ar$hln and ar$pln) are redundant, -since the length of a protocol address should be determined by -the hardware type (found in ar$hrd) and the protocol type (found -in ar$pro). It is included for optional consistency checking, -and for network monitoring and debugging (see below). - -The opcode is to determine if this is a request (which may cause -a reply) or a reply to a previous request. 16 bits for this is -overkill, but a flag (field) is needed. - -The sender hardware address and sender protocol address are -absolutely necessary. It is these fields that get put in a -translation table. - -The target protocol address is necessary in the request form of -the packet so that a machine can determine whether or not to -enter the sender information in a table or to send a reply. It -is not necessarily needed in the reply form if one assumes a -reply is only provoked by a request. It is included for -completeness, network monitoring, and to simplify the suggested -processing algorithm described above (which does not look at the -opcode until AFTER putting the sender information in a table). - -The target hardware address is included for completeness and -network monitoring. It has no meaning in the request form, since -it is this number that the machine is requesting. Its meaning in -the reply form is the address of the machine making the request. -In some implementations (which do not get to look at the 14.byte -ethernet header, for example) this may save some register -shuffling or stack space by sending this field to the hardware -driver as the hardware destination address of the packet. - -There are no padding bytes between addresses. The packet data -should be viewed as a byte stream in which only 3 byte pairs are -defined to be words (ar$hrd, ar$pro and ar$op) which are sent -most significant byte first (Ethernet/PDP-10 byte style). - - -Network monitoring and debugging: ---------------------------------- - -The above Address Resolution protocol allows a machine to gain -knowledge about the higher level protocol activity (e.g., CHAOS, -Internet, PUP, DECnet) on an Ethernet cable. It can determine -which Ethernet protocol type fields are in use (by value) and the -protocol addresses within each protocol type. In fact, it is not -necessary for the monitor to speak any of the higher level -protocols involved. It goes something like this: - -When a monitor receives an Address Resolution packet, it always -enters the in a table. It can determine the length of the -hardware and protocol address from the ar$hln and ar$pln fields -of the packet. If the opcode is a REPLY the monitor can then -throw the packet away. If the opcode is a REQUEST and the target -protocol address matches the protocol address of the monitor, the -monitor sends a REPLY as it normally would. The monitor will -only get one mapping this way, since the REPLY to the REQUEST -will be sent directly to the requesting host. The monitor could -try sending its own REQUEST, but this could get two monitors into -a REQUEST sending loop, and care must be taken. - -Because the protocol and opcode are not combined into one field, -the monitor does not need to know which request opcode is -associated with which reply opcode for the same higher level -protocol. The length fields should also give enough information -to enable it to "parse" a protocol addresses, although it has no -knowledge of what the protocol addresses mean. - -A working implementation of the Address Resolution protocol can -also be used to debug a non-working implementation. Presumably a -hardware driver will successfully broadcast a packet with Ethernet -type field of ether_type$ADDRESS_RESOLUTION. The format of the -packet may not be totally correct, because initial -implementations may have bugs, and table management may be -slightly tricky. Because requests are broadcast a monitor will -receive the packet and can display it for debugging if desired. - - -An Example: ------------ - -Let there exist machines X and Y that are on the same 10Mbit -Ethernet cable. They have Ethernet address EA(X) and EA(Y) and -DOD Internet addresses IPA(X) and IPA(Y) . Let the Ethernet type -of Internet be ET(IP). Machine X has just been started, and -sooner or later wants to send an Internet packet to machine Y on -the same cable. X knows that it wants to send to IPA(Y) and -tells the hardware driver (here an Ethernet driver) IPA(Y). The -driver consults the Address Resolution module to convert into a 48.bit Ethernet address, but because X was just -started, it does not have this information. It throws the -Internet packet away and instead creates an ADDRESS RESOLUTION -packet with - (ar$hrd) = ares_hrd$Ethernet - (ar$pro) = ET(IP) - (ar$hln) = length(EA(X)) - (ar$pln) = length(IPA(X)) - (ar$op) = ares_op$REQUEST - (ar$sha) = EA(X) - (ar$spa) = IPA(X) - (ar$tha) = don't care - (ar$tpa) = IPA(Y) -and broadcasts this packet to everybody on the cable. - -Machine Y gets this packet, and determines that it understands -the hardware type (Ethernet), that it speaks the indicated -protocol (Internet) and that the packet is for it -((ar$tpa)=IPA(Y)). It enters (probably replacing any existing -entry) the information that maps to EA(X). It -then notices that it is a request, so it swaps fields, putting -EA(Y) in the new sender Ethernet address field (ar$sha), sets the -opcode to reply, and sends the packet directly (not broadcast) to -EA(X). At this point Y knows how to send to X, but X still -doesn't know how to send to Y. - -Machine X gets the reply packet from Y, forms the map from - to EA(Y), notices the packet is a reply and -throws it away. The next time X's Internet module tries to send -a packet to Y on the Ethernet, the translation will succeed, and -the packet will (hopefully) arrive. If Y's Internet module then -wants to talk to X, this will also succeed since Y has remembered -the information from X's request for Address Resolution. - -Related issue: ---------------- - -It may be desirable to have table aging and/or timeouts. The -implementation of these is outside the scope of this protocol. -Here is a more detailed description (thanks to MOON@SCRC@MIT-MC). - -If a host moves, any connections initiated by that host will -work, assuming its own address resolution table is cleared when -it moves. However, connections initiated to it by other hosts -will have no particular reason to know to discard their old -address. However, 48.bit Ethernet addresses are supposed to be -unique and fixed for all time, so they shouldn't change. A host -could "move" if a host name (and address in some other protocol) -were reassigned to a different physical piece of hardware. Also, -as we know from experience, there is always the danger of -incorrect routing information accidentally getting transmitted -through hardware or software error; it should not be allowed to -persist forever. Perhaps failure to initiate a connection should -inform the Address Resolution module to delete the information on -the basis that the host is not reachable, possibly because it is -down or the old translation is no longer valid. Or perhaps -receiving of a packet from a host should reset a timeout in the -address resolution entry used for transmitting packets to that -host; if no packets are received from a host for a suitable -length of time, the address resolution entry is forgotten. This -may cause extra overhead to scan the table for each incoming -packet. Perhaps a hash or index can make this faster. - -The suggested algorithm for receiving address resolution packets -tries to lessen the time it takes for recovery if a host does -move. Recall that if the is already in the translation table, then the sender -hardware address supersedes the existing entry. Therefore, on a -perfect Ethernet where a broadcast REQUEST reaches all stations -on the cable, each station will be get the new hardware address. - -Another alternative is to have a daemon perform the timeouts. -After a suitable time, the daemon considers removing an entry. -It first sends (with a small number of retransmissions if needed) -an address resolution packet with opcode REQUEST directly to the -Ethernet address in the table. If a REPLY is not seen in a short -amount of time, the entry is deleted. The request is sent -directly so as not to bother every station on the Ethernet. Just -forgetting entries will likely cause useful information to be -forgotten, which must be regained. - -Since hosts don't transmit information about anyone other than -themselves, rebooting a host will cause its address mapping table -to be up to date. Bad information can't persist forever by being -passed around from machine to machine; the only bad information -that can exist is in a machine that doesn't know that some other -machine has changed its 48.bit Ethernet address. Perhaps -manually resetting (or clearing) the address mapping table will -suffice. - -This issue clearly needs more thought if it is believed to be -important. It is caused by any address resolution-like protocol. - diff --git a/ext/picotcp/RFC/rfc0872.txt b/ext/picotcp/RFC/rfc0872.txt deleted file mode 100644 index c53bcb2..0000000 --- a/ext/picotcp/RFC/rfc0872.txt +++ /dev/null @@ -1,549 +0,0 @@ - - - RFC 872 September 1982 - M82-48 - - - - - - - - TCP-ON-A-LAN - - - - - - - - - - - - - - - - - - - - - - M.A. PADLIPSKY - THE MITRE CORPORATION - Bedford, Massachusetts - - - - - - Abstract - - - - - The sometimes-held position that the DoD Standard - Transmission Control Protocol (TCP) and Internet Protocol (IP) - are inappropriate for use "on" a Local Area Network (LAN) is - shown to be fallacious. The paper is a companion piece to - M82-47, M82-49, M82-50, and M82-51. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i - - - - - "TCP-ON-A-LAN" - - M. A. Padlipsky - - Thesis - - It is the thesis of this paper that fearing "TCP-on-a-LAN" - is a Woozle which needs slaying. To slay the "TCP-on-a-LAN" - Woozle, we need to know three things: What's a Woozle? What's a - LAN? What's a TCP? - - Woozles - - The first is rather straightforward [1]: - - One fine winter's day when Piglet was brushing away the - snow in front of his house, he happened to look up, and - there was Winnie-the-Pooh. Pooh was walking round and round - in a circle, thinking of something else, and when Piglet - called to him, he just went on walking. - "Hallo!" said Piglet, "what are you doing?" - "Hunting," said Pooh. - "Hunting what?" - "Tracking something," said Winnie-the-Pooh very - mysteriously. - "Tracking what?" said Piglet, coming closer. - "That's just what I ask myself. I ask myself, What?" - "What do you think you'll answer?" - "I shall have to wait until I catch up with it," said - Winnie-the-Pooh. "Now look there." He pointed to the - ground in front of him. "What do you see there? - "Tracks," said Piglet, "Paw-marks." he gave a little - squeak of excitement. "Oh, Pooh! Do you think it's a--a--a - Woozle?" - - Well, they convince each other that it is a Woozle, keep - "tracking," convince each other that it's a herd of Hostile - Animals, and get duly terrified before Christopher Robin comes - along and points out that they were following their own tracks - all the long. - - In other words, it is our contention that expressed fears - about the consequences of using a particular protocol named "TCP" - in a particular environment called a Local Area Net stem from - misunderstandings of the protocol and the environment, not from - the technical facts of the situation. - - - - - - - 1 - RFC 872 September 1982 - - - LAN's - - The second thing we need to know is somewhat less - straightforward: A LAN is, properly speaking [2], a - communications mechanism (or subnetwork) employing a transmission - technology suitable for relatively short distances (typically a - few kilometers) at relatively high bit-per-second rates - (typically greater than a few hundred kilobits per second) with - relatively low error rates, which exists primarily to enable - suitably attached computer systems (or "Hosts") to exchange bits, - and secondarily, though not necessarily, to allow terminals of - the teletypewriter and CRT classes to exchange bits with Hosts. - The Hosts are, at least in principle, heterogeneous; that is, - they are not merely multiple instances of the same operating - system. The Hosts are assumed to communicate by means of layered - protocols in order to achieve what the ARPANET tradition calls - "resource sharing" and what the newer ISO tradition calls "Open - System Interconnection." Addressing typically can be either - Host-Host (point-to-point) or "broadcast." (In some environments, - e.g., Ethernet, interesting advantage can be taken of broadcast - addressing; in other environments, e.g., LAN's which are - constituents of ARPA- or ISO-style "internets", broadcast - addressing is deemed too expensive to implement throughout the - internet as a whole and so may be ignored in the constituent LAN - even if available as part of the Host-LAN interface.) - - Note that no assumptions are made about the particular - transmission medium or the particular topology in play. LAN - media can be twisted-pair wires, CATV or other coaxial-type - cables, optical fibers, or whatever. However, if the medium is a - processor-to-processor bus it is likely that the system in - question is going to turn out to "be" a moderately closely - coupled distributed processor or a somewhat loosely coupled - multiprocessor rather than a LAN, because the processors are - unlikely to be using either ARPANET or ISO-style layered - protocols. (They'll usually -- either be homogeneous processors - interpreting only the protocol necessary to use the transmission - medium, or heterogeneous with one emulating the expectations of - the other.) Systems like "PDSC" or "NMIC" (the evolutionarily - related, bus-oriented, multiple PDP-11 systems in use at the - Pacific Data Services Center and the National Military - Intelligence Center, respectively), then, aren't LANs. - - LAN topologies can be either "bus," "ring," or "star". That - is, a digital PBX can be a LAN, in the sense of furnishing a - transmission medium/communications subnetwork for Hosts to do - resource sharing/Open System Interconnection over, though it - might not present attractive speed or failure mode properties. - (It might, though.) Topologically, it would probably be a - neutron star. - - - - 2 - RFC 872 September 1982 - - - For our purposes, the significant properties of a LAN are - the high bit transmission capacity and the good error properties. - Intuitively, a medium with these properties in some sense - "shouldn't require a heavy-duty protocol designed for long-haul - nets," according to some. (We will not address the issue of - "wasted bandwidth" due to header sizes. [2], pp. 1509f, provides - ample refutation of that traditional communications notion.) - However, it must be borne in mind that for our purposes the - assumption of resource-sharing/OSI type protocols between/among - the attached Hosts is also extremely significant. That is, if - all you're doing is letting some terminals access some different - Hosts, but the Hosts don't really have any intercomputer - networking protocols between them, what you have should be viewed - as a Localized Communications Network (LCN), not a LAN in the - sense we're talking about here. - - TCP - - The third thing we have to know can be either - straightforward or subtle, depending largely on how aware we are - of the context estabished by ARPANET-style prococols: For the - visual-minded, Figure 1 and Figure 2 might be all that need be - "said." Their moral is meant to be that in ARPANET-style - layering, layers aren't monoliths. For those who need more - explanation, here goes: TCP [3] (we'll take IP later) is a - Host-Host protocol (roughly equivalent to the functionality - implied by some of ISO Level 5 and all of ISO Level 4). Its most - significant property is that it presents reliable logical - connections to protocols above itself. (This point will be - returned to subsequently.) Its next most significant property is - that it is designed to operate in a "catenet" (also known as the, - or an, "internet"); that is, its addressing discipline is such - that Hosts attached to communications subnets other than the one - a given Host is attached to (the "proximate net") can be - communicated with as well as Hosts on the proximate net. Other - significant properties are those common to the breed: Host-Host - protocols (and Transport protocols) "all" offer mechanisms for - flow Control, Out-of-Band Signals, Logical Connection management, - and the like. - - Because TCP has a catenet-oriented addressing mechanism - (that is, it expresses foreign Host addresses as the - "two-dimensional" entity Foreign Net/Foreign Host because it - cannot assume that the Foreign Host is attached to the proximate - net), to be a full Host-Host protocol it needs an adjunct to deal - with the proximate net. This adjunct, the Internet Protocol (IP) - was designed as a separate protocol from TCP, however, in order - to allow it to play the same role it plays for TCP for other - Host-Host protocols too. - - - - - 3 - RFC 872 September 1982 - - - In order to "deal with the proximate net", IP possess the - following significant properties: An IP implementation maps from - a virtualization (or common intermediate representation) of - generic proximate net qualities (such as precedence, grade of - service, security labeling) to the closest equivalent on the - proximate net. It determines whether the "Internet Address" of a - given transmission is on the proximate net or not; if so, it - sends it; if not, it sends it to a "Gateway" (where another IP - module resides). That is, IP handles internet routing, whereas - TCP (or some other Host-Host protocol) handles only internet - addressing. Because some proximate nets will accept smaller - transmissions ("packets") than others, IP, qua protocol, also has - a discipline for allowing packets to be fragmented while in the - catenet and reassembled at their destination. Finally (for our - purposes), IP offers a mechanism to allow the particular protocol - it was called by (for a given packet) to be identified so that - the receiver can demultiplex transmissions based on IP-level - information only. (This is in accordance with the Principle of - Layering: you don't want to have to look at the data IP is - conveying to find out what to do with it.) - - Now that all seems rather complex, even though it omits a - number of mechanisms. (For a more complete discussion, see - Reference [4].) But it should be just about enough to slay the - Woozle, especially if just one more protocol's most significant - property can be snuck in. An underpublicized member of the - ARPANET suite of protocols is called UDP--the "User Datagram - Protocol." UDP is designed for speed rather than accuracy. That - is, it's not "reliable." All there is to UDP, basically, is a - mechanism to allow a given packet to be associated with a given - logical connection. Not a TCP logical connection, mind you, but a - UDP logical connection. So if all you want is the ability to - demultiplex data streams from your Host-Host protocol, you use - UDP, not TCP. ("You" is usually supposed to be a Packetized - Speech protocol, but doesn't have to be.) (And we'll worry about - Flow Control some other time.) - - TCP-on-a-LAN - - So whether you're a Host proximate to a LAN or not, and even - whether your TCP/IP is "inboard" or "outboard" of you, if you're - talking to a Host somewhere out there on the catenet, you use IP; - and if you're exercising some process-level/applications protocol - (roughly equivalent to some of some versions of ISO L5 and all of - L6 and L7) that expects TCP/IP as its Host-Host protocol (because - it "wants" reliable, flow controlled, ordered delivery [whoops, - forgot that "ordered" property earlier--but it doesn't matter all - that much for present purposes] over logical connections which - allow it to be - - - - - 4 - RFC 872 September 1982 - - - addressed via a Well-Known Socket), you use TCP "above" IP - regardless of whether the other Host is on your proximate net or - not. But if your application doesn't require the properties of - TCP (say for Packetized Speech), don't use it--regardless of - where or what you are. And if you want to make the decision - about whether you're talking to a proximate Host explicitly and - not even go through IP, you can even arrange to do that (though - it might make for messy implementation under some circumstances). - That is, if you want to take advantage of the properties of your - LAN "in the raw" and have or don't need appropriate applications - protocols, the Reference Model to which TCP/IP were designed - won't stop you. See Figure 2 if you're visual. A word of - caution, though: those applications probably will need protocols - of some sort--and they'll probably need some sort of Host-Host - protocol under them, so unless you relish maintaining "parallel" - suites of protocols.... that is, you really would be better off - with TCP most of the time locally anyway, because you've got to - have it to talk to the catenet and it's a nuisance to have - "something else" to talk over the LAN--when, of course, what - you're talking requires a Host-Host protocol. - - We'll touch on "performance" issues in a bit more detail - later. At this level, though, one point really does need to be - made: On the "reliability" front, many (including the author) at - first blush take the TCP checksum to be "overkill" for use on a - LAN, which does, after all, typically present extremely good - error properties. Interestingly enough, however, metering of TCP - implementations on several Host types in the research community - shows that the processing time expended on the TCP checksum is - only around 12% of the per-transmission processing time anyway. - So, again, it's not clear that it's worthwhile to bother with an - alternate Host-Host protocol for local use (if, that is, you need - the rest of the properties of TCP other than "reliability"--and, - of course, always assuming you've got a LAN, not an LCN, as - distinguished earlier.) - - Take that, Woozle! - - Other Significant Properties - - Oh, by the way, one or two other properties of TCP/IP really - do bear mention: - - 1. Protocol interpreters for TCP/IP exist for a dozen or - two different operating systems. - - 2. TCP/IP work, and have been working (though in less - refined versions) for several years. - - - - - - 5 - RFC 872 September 1982 - - - 3. IP levies no constraints on the interface protocol - presented by the proximate net (though some protocols - at that level are more wasteful than others). - - 4. IP levies no constraints on its users; in particular, - any proximate net that offers alternate routing can be - taken advantage of (unlike X.25, which appears to - preclude alternate routing). - - 5. IP-bearing Gateways both exist and present and exploit - properties 3 and 4. - - 6. TCP/IP are Department of Defense Standards. - - 7. Process (or application) protocols compatible with - TCP/IP for Virtual Terminal and File Transfer - (including "electronic mail") exist and have been - implemented on numerous operating systems. - - 8. "Vendor-style" specifications of TCP/IP are being - prepared under the aegis of the DoD Protocol Standards - Technical Panel, for those who find the - research-community-provided specs not to their liking. - - 9. The research community has recently reported speeds in - excess of 300 kb/s on an 800 kb/s subnet, 1.2 Mb/s on a - 3 Mb/s subnet, and 9.2 kbs on a 9.6 kb/s phone - line--all using TCP. (We don't know of any numbers for - alternative protocol suites, but it's unlikely they'd - be appreciably better if they confer like - functionality--and they may well be worse if they - represent implementations which haven't been around - enough to have been iterated a time or three.) - - With the partial exception of property 8, no other - resource-sharing protocol suite can make those claims. - - Note particularly well that none of the above should be - construed as eliminating the need for extremely careful - measurement of TCP/IP performance in/on a LAN. (You do, after - all, want to know their limitations, to guide you in when to - bother ringing in "local" alternatives--but be very careful: 1. - they're hard to measure commensurately with alternative - protocols; and 2. most conventional Hosts can't take [or give] - as many bits per second as you might imagine.) It merely - dramatically refocuses the motivation for doing such measurement. - (And levies a constraint or two on how you outboard, if you're - outboarding.) - - - - - - 6 - RFC 872 September 1982 - - - Other Contextual Data - - Our case could really rest here, but some amplification of - the aside above about Host capacities is warranted, if only to - suggest that some quantification is available to supplement the a - priori argument: Consider the previously mentioned PDSC. Its - local terminals operate in a screen-at-a-time mode, each - screen-load comprising some 16 kb. How many screens can one of - its Hosts handle in a given second? Well, we're told that each - disk fetch requires 17 ms average latency, and each context - switch costs around 2 ms, so allowing 1 ms for transmission of - the data from the disk and to the "net" (it makes the arithmetic - easy), that would add up to 20 ms "processing" time per screen, - even if no processing were done to the disk image. Thus, even if - the Host were doing nothing else, and even if the native disk - I/O software were optimized to do 16 kb reads, it could only - present 50 screens to its communications mechanism - (processor-processor bus) per second. That's 800 kb/s. And - that's well within the range of TCP-achievable rates (cf. Other - Significant Property 9). So in a realistic sample environment, - it would certainly seem that typical Hosts can't necessarily - present so many bits as to overtax the protocols anyway. (The - analysis of how many bits typical Hosts can accept is more - difficult because it depends more heavily on system internals. - However, the point is nearly moot in that even in the intuitively - unlikely event that receiving were appreciably faster in - principle [unlikely because of typical operating system - constraints on address space sizes, the need to do input to a - single address space, and the need to share buffers in the - address space among several processes], you can't accept more - than you can be given.) - - Conclusion - - The sometimes-expressed fear that using TCP on a local net - is a bad idea is unfounded. - - References - - [1] Milne, A. A., "Winnie-the-Pooh", various publishers. - - [2] The LAN description is based on Clark, D. D. et al., "An - Introduction to Local Area Networks," IEEE Proc., V. 66, N. - 11, November 1978, pp. 1497-1517, several year's worth of - conversations with Dr. Clark, and the author's observations - of both the open literature and the Oral Tradition (which - were sufficiently well-thought of to have prompted The MITRE - Corporation/NBS/NSA Local Nets "Brain Picking Panel" to have - - - - - - 7 - RFC 872 September 1982 - - - solicited his testimony during the year he was in FACC's - employ.*) - - [3] The TCP/IP descriptions are based on Postel, J. B., - "Internet Protocol Specification," and "Transmission Control - Specification" in DARPA Internet Program Protocol - Specifications, USC Information Sciences Institute, - September, 1981, and on more than 10 years' worth of - conversations with Dr. Postel, Dr. Clark (now the DARPA - "Internet Architect") and Dr. Vinton G. Cerf (co-originator - of TCP), and on numerous discussions with several other - members of the TCP/IP design team, on having edited the - referenced documents for the PSTP, and, for that matter, on - having been one of the developers of the ARPANET "Reference - Model." - - [4] Padlipsky, M. A., "A Perspective on the ARPANET Reference - Model", M82-47, The MITRE Corporation, September 1982; also - available in Proc. INFOCOM '83. - - ________________ - * In all honesty, as far as I know I started the rumor that TCP - might be overkill for a LAN at that meeting. At the next TCP - design meeting, however, they separated IP out from TCP, and - everything's been alright for about three years now--except - for getting the rumor killed. (I'd worry about Woozles - turning into roosting chickens if it weren't for the facts - that: 1. People tend to ignore their local guru; 2. I was - trying to encourage the IP separation; and 3. All I ever - wanted was some empirical data.) - - NOTE: FIGURE 1. ARM in the Abstract, and FIGURE 2. ARMS, - Somewhat Particularized, may be obtained by writing to: Mike - Padlipsky, MITRE Corporation, P.O. Box 208, Bedford, - Massachusetts, 01730, or sending computer mail to - Padlipsky@USC-ISIA. - - - - - - - - - - - - - - - - - - 8 \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc0879.txt b/ext/picotcp/RFC/rfc0879.txt deleted file mode 100644 index fdde68e..0000000 --- a/ext/picotcp/RFC/rfc0879.txt +++ /dev/null @@ -1,638 +0,0 @@ - - -Network Working Group J. Postel -Request for Comments: 879 ISI - November 1983 - - - - The TCP Maximum Segment Size - and Related Topics - -This memo discusses the TCP Maximum Segment Size Option and related -topics. The purposes is to clarify some aspects of TCP and its -interaction with IP. This memo is a clarification to the TCP -specification, and contains information that may be considered as -"advice to implementers". - -1. Introduction - - This memo discusses the TCP Maximum Segment Size and its relation to - the IP Maximum Datagram Size. TCP is specified in reference [1]. IP - is specified in references [2,3]. - - This discussion is necessary because the current specification of - this TCP option is ambiguous. - - Much of the difficulty with understanding these sizes and their - relationship has been due to the variable size of the IP and TCP - headers. - - There have been some assumptions made about using other than the - default size for datagrams with some unfortunate results. - - HOSTS MUST NOT SEND DATAGRAMS LARGER THAN 576 OCTETS UNLESS THEY - HAVE SPECIFIC KNOWLEDGE THAT THE DESTINATION HOST IS PREPARED TO - ACCEPT LARGER DATAGRAMS. - - This is a long established rule. - - To resolve the ambiguity in the TCP Maximum Segment Size option - definition the following rule is established: - - THE TCP MAXIMUM SEGMENT SIZE IS THE IP MAXIMUM DATAGRAM SIZE MINUS - FORTY. - - The default IP Maximum Datagram Size is 576. - The default TCP Maximum Segment Size is 536. - - - - - - - - - -Postel [Page 1] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - -2. The IP Maximum Datagram Size - - Hosts are not required to reassemble infinitely large IP datagrams. - The maximum size datagram that all hosts are required to accept or - reassemble from fragments is 576 octets. The maximum size reassembly - buffer every host must have is 576 octets. Hosts are allowed to - accept larger datagrams and assemble fragments into larger datagrams, - hosts may have buffers as large as they please. - - Hosts must not send datagrams larger than 576 octets unless they have - specific knowledge that the destination host is prepared to accept - larger datagrams. - -3. The TCP Maximum Segment Size Option - - TCP provides an option that may be used at the time a connection is - established (only) to indicate the maximum size TCP segment that can - be accepted on that connection. This Maximum Segment Size (MSS) - announcement (often mistakenly called a negotiation) is sent from the - data receiver to the data sender and says "I can accept TCP segments - up to size X". The size (X) may be larger or smaller than the - default. The MSS can be used completely independently in each - direction of data flow. The result may be quite different maximum - sizes in the two directions. - - The MSS counts only data octets in the segment, it does not count the - TCP header or the IP header. - - A footnote: The MSS value counts only data octets, thus it does not - count the TCP SYN and FIN control bits even though SYN and FIN do - consume TCP sequence numbers. - -4. The Relationship of TCP Segments and IP Datagrams - - TCP segment are transmitted as the data in IP datagrams. The - correspondence between TCP segments and IP datagrams must be one to - one. This is because TCP expects to find exactly one complete TCP - segment in each block of data turned over to it by IP, and IP must - turn over a block of data for each datagram received (or completely - reassembled). - - - - - - - - - - -Postel [Page 2] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - -5. Layering and Modularity - - TCP is an end to end reliable data stream protocol with error - control, flow control, etc. TCP remembers many things about the - state of a connection. - - IP is a one shot datagram protocol. IP has no memory of the - datagrams transmitted. It is not appropriate for IP to keep any - information about the maximum datagram size a particular destination - host might be capable of accepting. - - TCP and IP are distinct layers in the protocol architecture, and are - often implemented in distinct program modules. - - Some people seem to think that there must be no communication between - protocol layers or program modules. There must be communication - between layers and modules, but it should be carefully specified and - controlled. One problem in understanding the correct view of - communication between protocol layers or program modules in general, - or between TCP and IP in particular is that the documents on - protocols are not very clear about it. This is often because the - documents are about the protocol exchanges between machines, not the - program architecture within a machine, and the desire to allow many - program architectures with different organization of tasks into - modules. - -6. IP Information Requirements - - There is no general requirement that IP keep information on a per - host basis. - - IP must make a decision about which directly attached network address - to send each datagram to. This is simply mapping an IP address into - a directly attached network address. - - There are two cases to consider: the destination is on the same - network, and the destination is on a different network. - - Same Network - - For some networks the the directly attached network address can - be computed from the IP address for destination hosts on the - directly attached network. - - For other networks the mapping must be done by table look up - (however the table is initialized and maintained, for - example, [4]). - - - -Postel [Page 3] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - - Different Network - - The IP address must be mapped to the directly attached network - address of a gateway. For networks with one gateway to the - rest of the Internet the host need only determine and remember - the gateway address and use it for sending all datagrams to - other networks. - - For networks with multiple gateways to the rest of the - Internet, the host must decide which gateway to use for each - datagram sent. It need only check the destination network of - the IP address and keep information on which gateway to use for - each network. - - The IP does, in some cases, keep per host routing information for - other hosts on the directly attached network. The IP does, in some - cases, keep per network routing information. - - A Special Case - - There are two ICMP messages that convey information about - particular hosts. These are subtypes of the Destination - Unreachable and the Redirect ICMP messages. These messages are - expected only in very unusual circumstances. To make effective - use of these messages the receiving host would have to keep - information about the specific hosts reported on. Because these - messages are quite rare it is strongly recommended that this be - done through an exception mechanism rather than having the IP keep - per host tables for all hosts. - -7. The Relationship between IP Datagram and TCP Segment Sizes - - The relationship between the value of the maximum IP datagram size - and the maximum TCP segment size is obscure. The problem is that - both the IP header and the TCP header may vary in length. The TCP - Maximum Segment Size option (MSS) is defined to specify the maximum - number of data octets in a TCP segment exclusive of TCP (or IP) - header. - - To notify the data sender of the largest TCP segment it is possible - to receive the calculation of the MSS value to send is: - - MSS = MTU - sizeof(TCPHDR) - sizeof(IPHDR) - - On receipt of the MSS option the calculation of the size of segment - that can be sent is: - - SndMaxSegSiz = MIN((MTU - sizeof(TCPHDR) - sizeof(IPHDR)), MSS) - - -Postel [Page 4] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - - where MSS is the value in the option, and MTU is the Maximum - Transmission Unit (or the maximum packet size) allowed on the - directly attached network. - - This begs the question, though. What value should be used for the - "sizeof(TCPHDR)" and for the "sizeof(IPHDR)"? - - There are three reasonable positions to take: the conservative, the - moderate, and the liberal. - - The conservative or pessimistic position assumes the worst -- that - both the IP header and the TCP header are maximum size, that is, 60 - octets each. - - MSS = MTU - 60 - 60 = MTU - 120 - - If MTU is 576 then MSS = 456 - - The moderate position assumes the that the IP is maximum size (60 - octets) and the TCP header is minimum size (20 octets), because there - are no TCP header options currently defined that would normally be - sent at the same time as data segments. - - MSS = MTU - 60 - 20 = MTU - 80 - - If MTU is 576 then MSS = 496 - - The liberal or optimistic position assumes the best -- that both the - IP header and the TCP header are minimum size, that is, 20 octets - each. - - MSS = MTU - 20 - 20 = MTU - 40 - - If MTU is 576 then MSS = 536 - - If nothing is said about MSS, the data sender may cram as much as - possible into a 576 octet datagram, and if the datagram has - minimum headers (which is most likely), the result will be 536 - data octets in the TCP segment. The rule relating MSS to the - maximum datagram size ought to be consistent with this. - - A practical point is raised in favor of the liberal position too. - Since the use of minimum IP and TCP headers is very likely in the - very large percentage of cases, it seems wasteful to limit the TCP - segment data to so much less than could be transmitted at once, - especially since it is less that 512 octets. - - - - -Postel [Page 5] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - - For comparison: 536/576 is 93% data, 496/576 is 86% data, 456/576 - is 79% data. - -8. Maximum Packet Size - - Each network has some maximum packet size, or maximum transmission - unit (MTU). Ultimately there is some limit imposed by the - technology, but often the limit is an engineering choice or even an - administrative choice. Different installations of the same network - product do not have to use the same maximum packet size. Even within - one installation not all host must use the same packet size (this way - lies madness, though). - - Some IP implementers have assumed that all hosts on the directly - attached network will be the same or at least run the same - implementation. This is a dangerous assumption. It has often - developed that after a small homogeneous set of host have become - operational additional hosts of different types are introduced into - the environment. And it has often developed that it is desired to - use a copy of the implementation in a different inhomogeneous - environment. - - Designers of gateways should be prepared for the fact that successful - gateways will be copied and used in other situation and - installations. Gateways must be prepared to accept datagrams as - large as can be sent in the maximum packets of the directly attached - networks. Gateway implementations should be easily configured for - installation in different circumstances. - - A footnote: The MTUs of some popular networks (note that the actual - limit in some installations may be set lower by administrative - policy): - - ARPANET, MILNET = 1007 - Ethernet (10Mb) = 1500 - Proteon PRONET = 2046 - -9. Source Fragmentation - - A source host would not normally create datagram fragments. Under - normal circumstances datagram fragments only arise when a gateway - must send a datagram into a network with a smaller maximum packet - size than the datagram. In this case the gateway must fragment the - datagram (unless it is marked "don't fragment" in which case it is - discarded, with the option of sending an ICMP message to the source - reporting the problem). - - It might be desirable for the source host to send datagram fragments - - -Postel [Page 6] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - - if the maximum segment size (default or negotiated) allowed by the - data receiver were larger than the maximum packet size allowed by the - directly attached network. However, such datagram fragments must not - combine to a size larger than allowed by the destination host. - - For example, if the receiving TCP announced that it would accept - segments up to 5000 octets (in cooperation with the receiving IP) - then the sending TCP could give such a large segment to the - sending IP provided the sending IP would send it in datagram - fragments that fit in the packets of the directly attached - network. - - There are some conditions where source host fragmentation would be - necessary. - - If the host is attached to a network with a small packet size (for - example 256 octets), and it supports an application defined to - send fixed sized messages larger than that packet size (for - example TFTP [5]). - - If the host receives ICMP Echo messages with data it is required - to send an ICMP Echo-Reply message with the same data. If the - amount of data in the Echo were larger than the packet size of the - directly attached network the following steps might be required: - (1) receive the fragments, (2) reassemble the datagram, (3) - interpret the Echo, (4) create an Echo-Reply, (5) fragment it, and - (6) send the fragments. - -10. Gateway Fragmentation - - Gateways must be prepared to do fragmentation. It is not an optional - feature for a gateway. - - Gateways have no information about the size of datagrams destination - hosts are prepared to accept. It would be inappropriate for gateways - to attempt to keep such information. - - Gateways must be prepared to accept the largest datagrams that are - allowed on each of the directly attached networks, even if it is - larger than 576 octets. - - Gateways must be prepared to fragment datagrams to fit into the - packets of the next network, even if it smaller than 576 octets. - - If a source host thought to take advantage of the local network's - ability to carry larger datagrams but doesn't have the slightest idea - if the destination host can accept larger than default datagrams and - expects the gateway to fragment the datagram into default size - - -Postel [Page 7] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - - fragments, then the source host is misguided. If indeed, the - destination host can't accept larger than default datagrams, it - probably can't reassemble them either. If the gateway either passes - on the large datagram whole or fragments into default size fragments - the destination will not accept it. Thus, this mode of behavior by - source hosts must be outlawed. - - A larger than default datagram can only arrive at a gateway because - the source host knows that the destination host can handle such large - datagrams (probably because the destination host announced it to the - source host in an TCP MSS option). Thus, the gateway should pass on - this large datagram in one piece or in the largest fragments that fit - into the next network. - - An interesting footnote is that even though the gateways may know - about know the 576 rule, it is irrelevant to them. - -11. Inter-Layer Communication - - The Network Driver (ND) or interface should know the Maximum - Transmission Unit (MTU) of the directly attached network. - - The IP should ask the Network Driver for the Maximum Transmission - Unit. - - The TCP should ask the IP for the Maximum Datagram Data Size (MDDS). - This is the MTU minus the IP header length (MDDS = MTU - IPHdrLen). - - When opening a connection TCP can send an MSS option with the value - equal MDDS - TCPHdrLen. - - TCP should determine the Maximum Segment Data Size (MSDS) from either - the default or the received value of the MSS option. - - TCP should determine if source fragmentation is possible (by asking - the IP) and desirable. - - If so TCP may hand to IP segments (including the TCP header) up to - MSDS + TCPHdrLen. - - If not TCP may hand to IP segments (including the TCP header) up - to the lesser of (MSDS + TCPHdrLen) and MDDS. - - IP checks the length of data passed to it by TCP. If the length is - less than or equal MDDS, IP attached the IP header and hands it to - the ND. Otherwise the IP must do source fragmentation. - - - - -Postel [Page 8] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - -12. What is the Default MSS ? - - Another way of asking this question is "What transmitted value for - MSS has exactly the same effect of not transmitting the option at - all?". - - In terms of the previous section: - - The default assumption is that the Maximum Transmission Unit is - 576 octets. - - MTU = 576 - - The Maximum Datagram Data Size (MDDS) is the MTU minus the IP - header length. - - MDDS = MTU - IPHdrLen = 576 - 20 = 556 - - When opening a connection TCP can send an MSS option with the - value equal MDDS - TCPHdrLen. - - MSS = MDDS - TCPHdrLen = 556 - 20 = 536 - - TCP should determine the Maximum Segment Data Size (MSDS) from - either the default or the received value of the MSS option. - - Default MSS = 536, then MSDS = 536 - - TCP should determine if source fragmentation is possible and - desirable. - - If so TCP may hand to IP segments (including the TCP header) up - to MSDS + TCPHdrLen (536 + 20 = 556). - - If not TCP may hand to IP segments (including the TCP header) - up to the lesser of (MSDS + TCPHdrLen (536 + 20 = 556)) and - MDDS (556). - - - - - - - - - - - - - -Postel [Page 9] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - -13. The Truth - - The rule relating the maximum IP datagram size and the maximum TCP - segment size is: - - TCP Maximum Segment Size = IP Maximum Datagram Size - 40 - - The rule must match the default case. - - If the TCP Maximum Segment Size option is not transmitted then the - data sender is allowed to send IP datagrams of maximum size (576) - with a minimum IP header (20) and a minimum TCP header (20) and - thereby be able to stuff 536 octets of data into each TCP segment. - - The definition of the MSS option can be stated: - - The maximum number of data octets that may be received by the - sender of this TCP option in TCP segments with no TCP header - options transmitted in IP datagrams with no IP header options. - -14. The Consequences - - When TCP is used in a situation when either the IP or TCP headers are - not minimum and yet the maximum IP datagram that can be received - remains 576 octets then the TCP Maximum Segment Size option must be - used to reduce the limit on data octets allowed in a TCP segment. - - For example, if the IP Security option (11 octets) were in use and - the IP maximum datagram size remained at 576 octets, then the TCP - should send the MSS with a value of 525 (536-11). - - - - - - - - - - - - - - - - - - - - -Postel [Page 10] - - - -RFC 879 November 1983 -TCP Maximum Segment Size - - -15. References - - [1] Postel, J., ed., "Transmission Control Protocol - DARPA Internet - Program Protocol Specification", RFC 793, USC/Information - Sciences Institute, September 1981. - - [2] Postel, J., ed., "Internet Protocol - DARPA Internet Program - Protocol Specification", RFC 791, USC/Information Sciences - Institute, September 1981. - - [3] Postel, J., "Internet Control Message Protocol - DARPA Internet - Program Protocol Specification", RFC 792, USC/Information - Sciences Institute, September 1981. - - [4] Plummer, D., "An Ethernet Address Resolution Protocol or - Converting Network Protocol Addresses to 48-bit Ethernet - Addresses for Transmission on Ethernet Hardware", RFC 826, - MIT/LCS, November 1982. - - [5] Sollins, K., "The TFTP Protocol (Revision 2)", RFC 783, MIT/LCS, - June 1981. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Postel [Page 11] - diff --git a/ext/picotcp/RFC/rfc0896.txt b/ext/picotcp/RFC/rfc0896.txt deleted file mode 100644 index d8a480a..0000000 --- a/ext/picotcp/RFC/rfc0896.txt +++ /dev/null @@ -1,512 +0,0 @@ - - -Network Working Group John Nagle -Request For Comments: 896 6 January 1984 - Ford Aerospace and Communications Corporation - - Congestion Control in IP/TCP Internetworks - -This memo discusses some aspects of congestion control in IP/TCP -Internetworks. It is intended to stimulate thought and further -discussion of this topic. While some specific suggestions are -made for improved congestion control implementation, this memo -does not specify any standards. - - Introduction - -Congestion control is a recognized problem in complex networks. -We have discovered that the Department of Defense's Internet Pro- -tocol (IP) , a pure datagram protocol, and Transmission Control -Protocol (TCP), a transport layer protocol, when used together, -are subject to unusual congestion problems caused by interactions -between the transport and datagram layers. In particular, IP -gateways are vulnerable to a phenomenon we call "congestion col- -lapse", especially when such gateways connect networks of widely -different bandwidth. We have developed solutions that prevent -congestion collapse. - -These problems are not generally recognized because these proto- -cols are used most often on networks built on top of ARPANET IMP -technology. ARPANET IMP based networks traditionally have uni- -form bandwidth and identical switching nodes, and are sized with -substantial excess capacity. This excess capacity, and the abil- -ity of the IMP system to throttle the transmissions of hosts has -for most IP / TCP hosts and networks been adequate to handle -congestion. With the recent split of the ARPANET into two inter- -connected networks and the growth of other networks with differ- -ing properties connected to the ARPANET, however, reliance on the -benign properties of the IMP system is no longer enough to allow -hosts to communicate rapidly and reliably. Improved handling of -congestion is now mandatory for successful network operation -under load. - -Ford Aerospace and Communications Corporation, and its parent -company, Ford Motor Company, operate the only private IP/TCP -long-haul network in existence today. This network connects four -facilities (one in Michigan, two in California, and one in Eng- -land) some with extensive local networks. This net is cross-tied -to the ARPANET but uses its own long-haul circuits; traffic -between Ford facilities flows over private leased circuits, -including a leased transatlantic satellite connection. All -switching nodes are pure IP datagram switches with no node-to- -node flow control, and all hosts run software either written or -heavily modified by Ford or Ford Aerospace. Bandwidth of links -in this network varies widely, from 1200 to 10,000,000 bits per -second. In general, we have not been able to afford the luxury -of excess long-haul bandwidth that the ARPANET possesses, and our -long-haul links are heavily loaded during peak periods. Transit -times of several seconds are thus common in our network. - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -Because of our pure datagram orientation, heavy loading, and wide -variation in bandwidth, we have had to solve problems that the -ARPANET / MILNET community is just beginning to recognize. Our -network is sensitive to suboptimal behavior by host TCP implemen- -tations, both on and off our own net. We have devoted consider- -able effort to examining TCP behavior under various conditions, -and have solved some widely prevalent problems with TCP. We -present here two problems and their solutions. Many TCP imple- -mentations have these problems; if throughput is worse through an -ARPANET / MILNET gateway for a given TCP implementation than -throughput across a single net, there is a high probability that -the TCP implementation has one or both of these problems. - - Congestion collapse - -Before we proceed with a discussion of the two specific problems -and their solutions, a description of what happens when these -problems are not addressed is in order. In heavily loaded pure -datagram networks with end to end retransmission, as switching -nodes become congested, the round trip time through the net -increases and the count of datagrams in transit within the net -also increases. This is normal behavior under load. As long as -there is only one copy of each datagram in transit, congestion is -under control. Once retransmission of datagrams not yet -delivered begins, there is potential for serious trouble. - -Host TCP implementations are expected to retransmit packets -several times at increasing time intervals until some upper limit -on the retransmit interval is reached. Normally, this mechanism -is enough to prevent serious congestion problems. Even with the -better adaptive host retransmission algorithms, though, a sudden -load on the net can cause the round-trip time to rise faster than -the sending hosts measurements of round-trip time can be updated. -Such a load occurs when a new bulk transfer, such a file -transfer, begins and starts filling a large window. Should the -round-trip time exceed the maximum retransmission interval for -any host, that host will begin to introduce more and more copies -of the same datagrams into the net. The network is now in seri- -ous trouble. Eventually all available buffers in the switching -nodes will be full and packets must be dropped. The round-trip -time for packets that are delivered is now at its maximum. Hosts -are sending each packet several times, and eventually some copy -of each packet arrives at its destination. This is congestion -collapse. - -This condition is stable. Once the saturation point has been -reached, if the algorithm for selecting packets to be dropped is -fair, the network will continue to operate in a degraded condi- -tion. In this condition every packet is being transmitted -several times and throughput is reduced to a small fraction of -normal. We have pushed our network into this condition experi- -mentally and observed its stability. It is possible for round- -trip time to become so large that connections are broken because - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -the hosts involved time out. - -Congestion collapse and pathological congestion are not normally -seen in the ARPANET / MILNET system because these networks have -substantial excess capacity. Where connections do not pass -through IP gateways, the IMP-to host flow control mechanisms usu- -ally prevent congestion collapse, especially since TCP implemen- -tations tend to be well adjusted for the time constants associ- -ated with the pure ARPANET case. However, other than ICMP Source -Quench messages, nothing fundamentally prevents congestion col- -lapse when TCP is run over the ARPANET / MILNET and packets are -being dropped at gateways. Worth noting is that a few badly- -behaved hosts can by themselves congest the gateways and prevent -other hosts from passing traffic. We have observed this problem -repeatedly with certain hosts (with whose administrators we have -communicated privately) on the ARPANET. - -Adding additional memory to the gateways will not solve the prob- -lem. The more memory added, the longer round-trip times must -become before packets are dropped. Thus, the onset of congestion -collapse will be delayed but when collapse occurs an even larger -fraction of the packets in the net will be duplicates and -throughput will be even worse. - - The two problems - -Two key problems with the engineering of TCP implementations have -been observed; we call these the small-packet problem and the -source-quench problem. The second is being addressed by several -implementors; the first is generally believed (incorrectly) to be -solved. We have discovered that once the small-packet problem -has been solved, the source-quench problem becomes much more -tractable. We thus present the small-packet problem and our -solution to it first. - - The small-packet problem - -There is a special problem associated with small packets. When -TCP is used for the transmission of single-character messages -originating at a keyboard, the typical result is that 41 byte -packets (one byte of data, 40 bytes of header) are transmitted -for each byte of useful data. This 4000% overhead is annoying -but tolerable on lightly loaded networks. On heavily loaded net- -works, however, the congestion resulting from this overhead can -result in lost datagrams and retransmissions, as well as exces- -sive propagation time caused by congestion in switching nodes and -gateways. In practice, throughput may drop so low that TCP con- -nections are aborted. - -This classic problem is well-known and was first addressed in the -Tymnet network in the late 1960s. The solution used there was to -impose a limit on the count of datagrams generated per unit time. -This limit was enforced by delaying transmission of small packets - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -until a short (200-500ms) time had elapsed, in hope that another -character or two would become available for addition to the same -packet before the timer ran out. An additional feature to -enhance user acceptability was to inhibit the time delay when a -control character, such as a carriage return, was received. - -This technique has been used in NCP Telnet, X.25 PADs, and TCP -Telnet. It has the advantage of being well-understood, and is not -too difficult to implement. Its flaw is that it is hard to come -up with a time limit that will satisfy everyone. A time limit -short enough to provide highly responsive service over a 10M bits -per second Ethernet will be too short to prevent congestion col- -lapse over a heavily loaded net with a five second round-trip -time; and conversely, a time limit long enough to handle the -heavily loaded net will produce frustrated users on the Ethernet. - - The solution to the small-packet problem - -Clearly an adaptive approach is desirable. One would expect a -proposal for an adaptive inter-packet time limit based on the -round-trip delay observed by TCP. While such a mechanism could -certainly be implemented, it is unnecessary. A simple and -elegant solution has been discovered. - -The solution is to inhibit the sending of new TCP segments when -new outgoing data arrives from the user if any previously -transmitted data on the connection remains unacknowledged. This -inhibition is to be unconditional; no timers, tests for size of -data received, or other conditions are required. Implementation -typically requires one or two lines inside a TCP program. - -At first glance, this solution seems to imply drastic changes in -the behavior of TCP. This is not so. It all works out right in -the end. Let us see why this is so. - -When a user process writes to a TCP connection, TCP receives some -data. It may hold that data for future sending or may send a -packet immediately. If it refrains from sending now, it will -typically send the data later when an incoming packet arrives and -changes the state of the system. The state changes in one of two -ways; the incoming packet acknowledges old data the distant host -has received, or announces the availability of buffer space in -the distant host for new data. (This last is referred to as -"updating the window"). Each time data arrives on a connec- -tion, TCP must reexamine its current state and perhaps send some -packets out. Thus, when we omit sending data on arrival from the -user, we are simply deferring its transmission until the next -message arrives from the distant host. A message must always -arrive soon unless the connection was previously idle or communi- -cations with the other end have been lost. In the first case, -the idle connection, our scheme will result in a packet being -sent whenever the user writes to the TCP connection. Thus we do -not deadlock in the idle condition. In the second case, where - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -the distant host has failed, sending more data is futile anyway. -Note that we have done nothing to inhibit normal TCP retransmis- -sion logic, so lost messages are not a problem. - -Examination of the behavior of this scheme under various condi- -tions demonstrates that the scheme does work in all cases. The -first case to examine is the one we wanted to solve, that of the -character-oriented Telnet connection. Let us suppose that the -user is sending TCP a new character every 200ms, and that the -connection is via an Ethernet with a round-trip time including -software processing of 50ms. Without any mechanism to prevent -small-packet congestion, one packet will be sent for each charac- -ter, and response will be optimal. Overhead will be 4000%, but -this is acceptable on an Ethernet. The classic timer scheme, -with a limit of 2 packets per second, will cause two or three -characters to be sent per packet. Response will thus be degraded -even though on a high-bandwidth Ethernet this is unnecessary. -Overhead will drop to 1500%, but on an Ethernet this is a bad -tradeoff. With our scheme, every character the user types will -find TCP with an idle connection, and the character will be sent -at once, just as in the no-control case. The user will see no -visible delay. Thus, our scheme performs as well as the no- -control scheme and provides better responsiveness than the timer -scheme. - -The second case to examine is the same Telnet test but over a -long-haul link with a 5-second round trip time. Without any -mechanism to prevent small-packet congestion, 25 new packets -would be sent in 5 seconds.* Overhead here is 4000%. With the -classic timer scheme, and the same limit of 2 packets per second, -there would still be 10 packets outstanding and contributing to -congestion. Round-trip time will not be improved by sending many -packets, of course; in general it will be worse since the packets -will contend for line time. Overhead now drops to 1500%. With -our scheme, however, the first character from the user would find -an idle TCP connection and would be sent immediately. The next -24 characters, arriving from the user at 200ms intervals, would -be held pending a message from the distant host. When an ACK -arrived for the first packet at the end of 5 seconds, a single -packet with the 24 queued characters would be sent. Our scheme -thus results in an overhead reduction to 320% with no penalty in -response time. Response time will usually be improved with our -scheme because packet overhead is reduced, here by a factor of -4.7 over the classic timer scheme. Congestion will be reduced by -this factor and round-trip delay will decrease sharply. For this -________ - * This problem is not seen in the pure ARPANET case because the - IMPs will block the host when the count of packets - outstanding becomes excessive, but in the case where a pure - datagram local net (such as an Ethernet) or a pure datagram - gateway (such as an ARPANET / MILNET gateway) is involved, it - is possible to have large numbers of tiny packets - outstanding. - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -case, our scheme has a striking advantage over either of the -other approaches. - -We use our scheme for all TCP connections, not just Telnet con- -nections. Let us see what happens for a file transfer data con- -nection using our technique. The two extreme cases will again be -considered. - -As before, we first consider the Ethernet case. The user is now -writing data to TCP in 512 byte blocks as fast as TCP will accept -them. The user's first write to TCP will start things going; our -first datagram will be 512+40 bytes or 552 bytes long. The -user's second write to TCP will not cause a send but will cause -the block to be buffered. Assume that the user fills up TCP's -outgoing buffer area before the first ACK comes back. Then when -the ACK comes in, all queued data up to the window size will be -sent. From then on, the window will be kept full, as each ACK -initiates a sending cycle and queued data is sent out. Thus, -after a one round-trip time initial period when only one block is -sent, our scheme settles down into a maximum-throughput condi- -tion. The delay in startup is only 50ms on the Ethernet, so the -startup transient is insignificant. All three schemes provide -equivalent performance for this case. - -Finally, let us look at a file transfer over the 5-second round -trip time connection. Again, only one packet will be sent until -the first ACK comes back; the window will then be filled and kept -full. Since the round-trip time is 5 seconds, only 512 bytes of -data are transmitted in the first 5 seconds. Assuming a 2K win- -dow, once the first ACK comes in, 2K of data will be sent and a -steady rate of 2K per 5 seconds will be maintained thereafter. -Only for this case is our scheme inferior to the timer scheme, -and the difference is only in the startup transient; steady-state -throughput is identical. The naive scheme and the timer scheme -would both take 250 seconds to transmit a 100K byte file under -the above conditions and our scheme would take 254 seconds, a -difference of 1.6%. - -Thus, for all cases examined, our scheme provides at least 98% of -the performance of both other schemes, and provides a dramatic -improvement in Telnet performance over paths with long round trip -times. We use our scheme in the Ford Aerospace Software -Engineering Network, and are able to run screen editors over Eth- -ernet and talk to distant TOPS-20 hosts with improved performance -in both cases. - - Congestion control with ICMP - -Having solved the small-packet congestion problem and with it the -problem of excessive small-packet congestion within our own net- -work, we turned our attention to the problem of general conges- -tion control. Since our own network is pure datagram with no -node-to-node flow control, the only mechanism available to us - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -under the IP standard was the ICMP Source Quench message. With -careful handling, we find this adequate to prevent serious -congestion problems. We do find it necessary to be careful about -the behavior of our hosts and switching nodes regarding Source -Quench messages. - - When to send an ICMP Source Quench - -The present ICMP standard* specifies that an ICMP Source Quench -message should be sent whenever a packet is dropped, and addi- -tionally may be sent when a gateway finds itself becoming short -of resources. There is some ambiguity here but clearly it is a -violation of the standard to drop a packet without sending an -ICMP message. - -Our basic assumption is that packets ought not to be dropped dur- -ing normal network operation. We therefore want to throttle -senders back before they overload switching nodes and gateways. -All our switching nodes send ICMP Source Quench messages well -before buffer space is exhausted; they do not wait until it is -necessary to drop a message before sending an ICMP Source Quench. -As demonstrated in our analysis of the small-packet problem, -merely providing large amounts of buffering is not a solution. -In general, our experience is that Source Quench should be sent -when about half the buffering space is exhausted; this is not -based on extensive experimentation but appears to be a reasonable -engineering decision. One could argue for an adaptive scheme -that adjusted the quench generation threshold based on recent -experience; we have not found this necessary as yet. - -There exist other gateway implementations that generate Source -Quenches only after more than one packet has been discarded. We -consider this approach undesirable since any system for control- -ling congestion based on the discarding of packets is wasteful of -bandwidth and may be susceptible to congestion collapse under -heavy load. Our understanding is that the decision to generate -Source Quenches with great reluctance stems from a fear that ack- -nowledge traffic will be quenched and that this will result in -connection failure. As will be shown below, appropriate handling -of Source Quench in host implementations eliminates this possi- -bility. - - What to do when an ICMP Source Quench is received - -We inform TCP or any other protocol at that layer when ICMP -receives a Source Quench. The basic action of our TCP implemen- -tations is to reduce the amount of data outstanding on connec- -tions to the host mentioned in the Source Quench. This control is -________ - * ARPANET RFC 792 is the present standard. We are advised by - the Defense Communications Agency that the description of - ICMP in MIL-STD-1777 is incomplete and will be deleted from - future revision of that standard. - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -applied by causing the sending TCP to behave as if the distant -host's window size has been reduced. Our first implementation -was simplistic but effective; once a Source Quench has been -received our TCP behaves as if the window size is zero whenever -the window isn't empty. This behavior continues until some -number (at present 10) of ACKs have been received, at that time -TCP returns to normal operation.* David Mills of Linkabit Cor- -poration has since implemented a similar but more elaborate -throttle on the count of outstanding packets in his DCN systems. -The additional sophistication seems to produce a modest gain in -throughput, but we have not made formal tests. Both implementa- -tions effectively prevent congestion collapse in switching nodes. - -Source Quench thus has the effect of limiting the connection to a -limited number (perhaps one) of outstanding messages. Thus, com- -munication can continue but at a reduced rate, that is exactly -the effect desired. - -This scheme has the important property that Source Quench doesn't -inhibit the sending of acknowledges or retransmissions. Imple- -mentations of Source Quench entirely within the IP layer are usu- -ally unsuccessful because IP lacks enough information to throttle -a connection properly. Holding back acknowledges tends to pro- -duce retransmissions and thus unnecessary traffic. Holding back -retransmissions may cause loss of a connection by a retransmis- -sion timeout. Our scheme will keep connections alive under -severe overload but at reduced bandwidth per connection. - -Other protocols at the same layer as TCP should also be respon- -sive to Source Quench. In each case we would suggest that new -traffic should be throttled but acknowledges should be treated -normally. The only serious problem comes from the User Datagram -Protocol, not normally a major traffic generator. We have not -implemented any throttling in these protocols as yet; all are -passed Source Quench messages by ICMP but ignore them. - - Self-defense for gateways - -As we have shown, gateways are vulnerable to host mismanagement -of congestion. Host misbehavior by excessive traffic generation -can prevent not only the host's own traffic from getting through, -but can interfere with other unrelated traffic. The problem can -be dealt with at the host level but since one malfunctioning host -can interfere with others, future gateways should be capable of -defending themselves against such behavior by obnoxious or mali- -cious hosts. We offer some basic self-defense techniques. - -On one occasion in late 1983, a TCP bug in an ARPANET host caused -the host to frantically generate retransmissions of the same -datagram as fast as the ARPANET would accept them. The gateway -________ - * This follows the control engineering dictum "Never bother - with proportional control unless bang-bang doesn't work". - - -RFC 896 Congestion Control in IP/TCP Internetworks 1/6/84 - - -that connected our net with the ARPANET was saturated and little -useful traffic could get through, since the gateway had more -bandwidth to the ARPANET than to our net. The gateway busily -sent ICMP Source Quench messages but the malfunctioning host -ignored them. This continued for several hours, until the mal- -functioning host crashed. During this period, our network was -effectively disconnected from the ARPANET. - -When a gateway is forced to discard a packet, the packet is -selected at the discretion of the gateway. Classic techniques -for making this decision are to discard the most recently -received packet, or the packet at the end of the longest outgoing -queue. We suggest that a worthwhile practical measure is to dis- -card the latest packet from the host that originated the most -packets currently queued within the gateway. This strategy will -tend to balance throughput amongst the hosts using the gateway. -We have not yet tried this strategy, but it seems a reasonable -starting point for gateway self-protection. - -Another strategy is to discard a newly arrived packet if the -packet duplicates a packet already in the queue. The computa- -tional load for this check is not a problem if hashing techniques -are used. This check will not protect against malicious hosts -but will provide some protection against TCP implementations with -poor retransmission control. Gateways between fast local net- -works and slower long-haul networks may find this check valuable -if the local hosts are tuned to work well with the local network. - -Ideally the gateway should detect malfunctioning hosts and -squelch them; such detection is difficult in a pure datagram sys- -tem. Failure to respond to an ICMP Source Quench message, -though, should be regarded as grounds for action by a gateway to -disconnect a host. Detecting such failure is non-trivial but is -a worthwhile area for further research. - - Conclusion - -The congestion control problems associated with pure datagram -networks are difficult, but effective solutions exist. If IP / -TCP networks are to be operated under heavy load, TCP implementa- -tions must address several key issues in ways at least as effec- -tive as the ones described here. - diff --git a/ext/picotcp/RFC/rfc0964.txt b/ext/picotcp/RFC/rfc0964.txt deleted file mode 100644 index ba78650..0000000 --- a/ext/picotcp/RFC/rfc0964.txt +++ /dev/null @@ -1,570 +0,0 @@ - - -Network Working Group Deepinder P. Sidhu -Request for Comments: 964 Thomas P. Blumer - SDC - A Burroughs Company - November 1985 - - SOME PROBLEMS WITH THE SPECIFICATION OF THE - MILITARY STANDARD TRANSMISSION CONTROL PROTOCOL - - -STATUS OF THIS MEMO - - The purpose of this RFC is to provide helpful information on the - Military Standard Transmission Control Protocol (MIL-STD-1778) so - that one can obtain a reliable implementation of this protocol - standard. Distribution of this note is unlimited. - - Reprinted from: Proc. Protocol Specification, Testing and - Verification IV, (ed.) Y. Yemini, et al, North-Holland (1984). - -ABSTRACT - - This note points out three errors with the specification of the - Military Standard Transmission Control Protocol (MIL-STD-1778, dated - August 1983 [MILS83]). These results are based on an initial - investigation of this protocol standard. The first problem is that - data accompanying a SYN can not be accepted because of errors in the - acceptance policy. The second problem is that no retransmission - timer is set for a SYN packet, and therefore the SYN will not be - retransmitted if it is lost. The third problem is that when the - connection has been established, neither entity takes the proper - steps to accept incoming data. This note also proposes solutions to - these problems. - -1. Introduction - - In recent years, much progress has been made in creating an - integrated set of tools for developing reliable communication - protocols. These tools provide assistance in the specification, - verification, implementation and testing of protocols. Several - protocols have been analyzed and developed using such tools. - - In a recent paper, the authors discussed the verification of the - connection management of NBS class 4 transport protocol (TP4). The - verification was carried out with the help of a software tool we - developed [BLUT82] [BLUT83] [SIDD83]. In spite of the very precise - specification of this protocol, our analysis discovered several - errors in the current specification of NBS TP4. These errors are - incompleteness errors in the specification, that is, states where - there is no transition for the reception of some input event. Our - analysis did not find deadlocks, livelocks or any other problem in - the connection management of TP4. In that paper, we proposed - - -Sidhu & Blumer [Page 1] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - - solutions for all errors except for errors associated with 2 states - whose satisfactory resolution may require redesigning parts of TP4. - Modifications to TP4 specification are currently underway to solve - the remaining incompleteness problems with 2 states. It is important - to emphasize that we did not find any obvious error in the NBS - specification of TP4. - - The authors are currently working on the verification of connection - management of the Military Standard Transmission Control Protocol - (TCP). This analysis will be based on the published specification - [MILS83] of TCP dated 12 August 1983. - - While studying the MIL standard TCP specification in preparation for - our analysis of the connection management features, we have noticed - several errors in the specification. As a consequence of these - errors, the Transmission Control Protocol (as specified in [MILS83]) - will not permit data to be received by TCP entities in SYN_RECVD and - ESTAB states. - - The proof of this statement follows from the specification of the - three-way handshake mechanism of TCP [MILS83] and from a decision - table associated with ESTAB state. - -2. Transmission Control Protocol - - The Transmission Control Protocol (TCP) is a transport level - connection-oriented protocol in the DoD protocol hierarchy for use in - packet-switched and other networks. Its most important services are - reliable transfer and ordered delivery of data over full-duplex and - flow-controlled virtual connections. TCP is designed to operate - successfully over channels that are inherently unreliable, i.e., they - can lose, damage, duplicate, and reorder packets. - - TCP is based, in part, on a protocol discussed by Cerf and Kahn - [CERV74]. Over the years, DARPA has supported specifications of - several versions of this protocol, the last one appeared in [POSJ81]. - Some issues in the connection management of this protocol are - discussed in [SUNC78]. - - A few years ago, DCA decided to standardize TCP for use in DoD - networks and supported formal specification of this protocol - following the design of this protocol discussed in [POSJ81]. A - detailed specification of this protocol given in [MILS83] has been - adopted as the DoD standard for the Transmission Control Protocol, a - reliable connection-oriented transport protocol for DoD networks. - - A TCP connection progresses through three phases: opening (or - - -Sidhu & Blumer [Page 2] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - - synchronization), maintenance, and closing. In this note we consider - data transfer in the opening and maintenance phases of the - connection. - -3. Problems with MIL Standard TCP - - One basic feature of TCP is the three-way handshake which is used to - set up a properly synchronized connection between two remote TCP - entities. This mechanism is incorrectly specified in the current - specification of TCP. One problem is that data associated with the - SYN packet can not be delivered. This results from an incorrect - specification of the interaction between the accept_policy action - procedure and the record_syn action procedure. Neither of the 2 - possible strategies suggested in accept_policy will give the correct - result when called from the record_syn procedure, because the - recv_next variable is updated in record_syn before the accept_policy - procedure is called. - - Another problem with the specification of the three-way handshake is - apparent in the actions listed for the Active Open event (with or - without data) when in the CLOSED state. No retransmission timer is - set in these actions, and therefore if the initial SYN is lost, there - will be no timer expiration to trigger retransmission. This will - prevent connection establishment if the initial SYN packet is lost by - the network. - - The third problem with the specification is that the actions for - receiving data in the ESTAB state are incorrect. The accept action - procedure must be called when data is received, so that arriving data - may be queued and possibly passed to the user. - - A general problem with this specification is that the program - language and action table portions of the specification were clearly - not checked by any automatic syntax checking process. Several - variable and procedure names are misspelled, and the syntax of the - action statements is often incorrect. This can be confusing, - especially when a procedure name cannot be found in the alphabetized - list of procedures because of misspelling. - - These are some of the very serious errors that we have discovered - with the MIL standard TCP. - - - - - - - - -Sidhu & Blumer [Page 3] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - -4. Detailed Discussion of the Problem - - Problem 1: Problem with Receiving Data Accompanying SYN - - The following scenario traces the actions of 2 communicating - entities during the establishment of a connection. Only the - simplest case is considered, i.e., the case where the connection - is established by the exchange of 3 segments. - - TCP entity A TCP entity B - ------------ ------------ - - state segment segment state - transition recvd or sent recvd or sent transition - by A by B - - CLOSED -> LISTEN - - CLOSED -> SYN_SENT SYN --> - - SYN --> LISTEN -> SYN_RECVD - <-- SYN ACK - - SYN_SENT -> ESTAB <-- SYN ACK - ACK --> - - ACK --> SYN_RECVD -> ESTAB - - As shown in the above diagram, 5 state transitions occur and 3 TCP - segments are exchanged during the simplest case of the three-way - handshake. We now examine in detail the actions of each entity - during this exchange. Special attention is given to the sequence - numbers carried in each packet and recorded in the state variables - of each entity. - - In the diagram below, the actions occurring within a procedure are - shown indented from the procedure call. The resulting values of - sequence number variables are shown in square brackets to the - right of each statement. The sequence number variables are shown - with the entity name (A or B) as prefix so that the two sets of - state variables may be easily distinguished. - - - - - - - - -Sidhu & Blumer [Page 4] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - - Transition 1 (entity B goes from state CLOSED to state LISTEN). - The user associated with entity B issues a Passive Open. - - Actions: (see p. 104) - open; (see p. 144) - new state := LISTEN; - - Transition 2 (entity A goes from state CLOSED to SYN_SENT). The - user associated with entity A issues an Active Open with Data. - - Actions: (see p. 104) - open; (see p. 144) - gen_syn(WITH_DATA); (see p. 141) - send_isn := gen_isn(); [A.send_isn = 100] - send_next := send_isn + 1; [A.send_next = 101] - send_una := send_isn; [A.send_una = 100] - seg.seq_num := send_isn; [seg.seq_num = 100] - seg.ack_flag := FALSE; [seg.ack_flag = FALSE] - seg.wndw := 0; [seg.wndw = 0] - amount := send_policy() [assume amount > 0] - new state := SYN_SENT; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Sidhu & Blumer [Page 5] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - - Transition 3 (Entity B goes from state LISTEN to state SYN_RECVD). - Entity B receives the SYN segment accompanying data sent by entity - A. - - Actions: (see p. 106) - (since this segment has no RESET, no ACK, does have SYN, and - we assume reasonable security and precedence parameters, row - 3 of the table applies) - record_syn; (see p. 147) - recv_isn := seg.seq_num; [B.recv_isn = seg_seq_num = 100] - recv_next := recv_isn + 1; [B.recv_next = 101] - if seg.ack_flag then - send_una := seg.ack_num; [no change] - accept_policy; (see p. 131) - Accept in-order data only: - Acceptance Test is - seg.seq_num = recv_next; - Accept any data within the receive window: - Acceptance Test has two parts - recv_next =< seg.seq_num =< recv_next + - recv_wndw - or - recv_next =< seg.seq_num + length =< - recv_next + recv_wndw - ******************************************** - An error occurs here, with either possible - strategy given in accept_policy, because - recv_next > seg.seq_num. Therefore - accept_policy will incorrectly indicate that - the data cannot be accepted. - ******************************************** - gen_syn(WITH_ACK); (see p. 141) - send_isn := gen_isn(); [B.send_isn = 300] - send_next := send_isn + 1; [B.send_next = 301] - send_una := send_isn; [B.send_una = 300] - seg.seq_num := send_next; [seg.seq_num = 301] - seg.ack_flag := TRUE; [seg.ack_flag = TRUE] - seg.ack_num := recv_isn + 1; [seg.ack_num = 102] - new state := SYN_RECVD; - - - - - - - - - - -Sidhu & Blumer [Page 6] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - - Transition 4 (entity A goes from state SYN_SENT to ESTAB) Entity A - receives the SYN ACK sent by entity B. - - Actions: (see p. 107) - In order to select the applicable row of the table on p. - 107, we first evaluate the decision function - ACK_status_test1. - ACK_status_test1(); - if(seg.ack_flag = FALSE) then - return(NONE); - if(seg.ack_num <= send_una) or - (seg.ack_num > send_next) then - return(INVALID) - else - return(VALID); - - ... and so on. - - The important thing to notice in the above scenario is the error - that occurs in transition 3, where the wrong value for recv_next - leads to the routine record_syn refusing to accept the data. - - Problem 2: Problem with Retransmission of SYN Packet - - The actions listed for Active Open (with or without data; see p. - 103) are calls to the routines open and gen_syn. Neither of these - routines (or routines that they call) explicitly sets a - retransmission timer. Therefore if the initial SYN is lost there - is no timer expiration to trigger retransmission of the SYN. If - this happens, the TCP will fail in its attempt to establish the - desired connection with a remote TCP. - - Note that this differs with the actions specified for transmission - of data from the ESTAB state. In that transition the routine - dispatch (p. 137) is called first which in turn calls the routine - send_new_data (p. 156). One of actions of the last routine is to - start a retransmission timer for the newly sent data. - - - - - - - - - - - - -Sidhu & Blumer [Page 7] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - - Problem 3: Problem with Receiving Data in TCP ESTAB State - - When both entities are in the state ESTAB, and one sends data to - the other, an error in the actions of the receiver prohibits the - data from being accepted. The following simple scenario - illustrates the problem. Here the user associated with entity A - issues a Send request, and A sends data to entity B. When B - receives the data it replies with an acknowledgment. - - TCP entity A TCP entity B - ------------ ------------ - - state segment segment state - transition recvd or sent recvd or sent transition - by A by B - - ESTAB -> ESTAB DATA --> - - DATA --> ESTAB -> ESTAB - <-- ACK - - Transition 1 (entity A goes from state ESTAB to ESTAB) Entity A - sends data packet to entity B. - - Actions: (see p. 110) - dispatch; (see p. 137) - - Transition 2 (entity B goes from state ESTAB to ESTAB) Entity B - receives data packet from entity B. - - Actions: (see p. 111) - Assuming the data is in order and valid, we use row 6 of the - table. - update; (see p. 159) - ************************************************************ - An error occurs here, because the routine update does - nothing to accept the incoming data, or to arrange to - pass it on to the user. - ************************************************************ - - - - - - - - - - -Sidhu & Blumer [Page 8] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - -5. Solutions to Problems - - The problem with record_syn and accept_policy can be solved by having - record_syn call accept_policy before the variable recv_next is - updated. - - The problem with gen_syn can be corrected by having gen_syn or open - explicitly request the retransmission timer. - - The problem with the reception of data in the ESTAB state is - apparently caused by the transposition of the action tables on pages - 111 and 112. These tables should be interchanged. This solution - will also correct a related problem, namely that an entity can never - reach the CLOSE_WAIT state from the ESTAB state. - - Syntax errors in the action statements and tables could be easily - caught by an automatic syntax checker if the document used a more - formal description technique. This would be difficult to do for - [MILS83] since this document is not based on a formalized description - technique [BREM83]. - - The errors pointed out in this note have been submitted to DCA and - will be corrected in the next update of the MIL STD TCP - specification. - -6. Implementation of MIL Standard TCP - - In the discussion above, we pointed out several serious errors in the - specification of the Military Standard Transmission Control Protocol - [MILS83]. These errors imply that a TCP implementation that - faithfully conforms to the Military TCP standard will not be able to - - Receive data sent with a SYN packet. - - Establish a connection if the initial SYN packet is lost. - - Receive data when in the ESTAB state. - - It also follows from our discussion that an implementation of MIL - Standard TCP [MILS83] must include corrections mentioned above to get - a running TCP. - - The problems pointed out in this paper with the current specification - of the MIL Standard TCP [MILS83] are based on an initial - investigation of this protocol standard by the authors. - - - - -Sidhu & Blumer [Page 9] - - - -RFC 964 November 1985 -Some Problems with MIL-STD TCP - - -REFERENCES - - [BLUT83] Blumer, T. P., and Sidhu, D. P., "Mechanical Verification - and Automatic Implementation of Authentication Protocols - for Computer Networks", SDC Burroughs Report (1983), - submitted for publication. - - [BLUT82] Blumer, T. P., and Tenney, R. L., "A Formal Specification - Technique and Implementation Method for Protocols", - Computer Networks, Vol. 6, No. 3, July 1982, pp. 201-217. - - [BREM83] Breslin, M., Pollack, R. and Sidhu D. P., "Formalization of - DoD Protocol Specification Technique", SDC - Burroughs - Report 1983. - - [CERV74] Cerf, V., and Kahn, R., "A Protocol for Packet Network - Interconnection", IEEE Trans. Comm., May 1974. - - [MILS83] "Military Standard Transmission Control Protocol", - MIL-STD-1778, 12 August 1983. - - [POSJ81] Postel, J. (ed.), "DoD Standard Transmission Control - Protocol", Defense Advanced Research Projects Agency, - Information Processing Techniques Office, RFC-793, - September 1981. - - [SIDD83] Sidhu, D. P., and Blumer, T. P., "Verification of NBS Class - 4 Transport Protocol", SDC Burroughs Report (1983), - submitted for publication. - - [SUNC78] Sunshine, C., and Dalal, Y., "Connection Management in - Transport Protocols", Computer Networks, Vol. 2, pp.454-473 - (1978). - - - - - - - - - - - - - - - - -Sidhu & Blumer [Page 10] - diff --git a/ext/picotcp/RFC/rfc1071.txt b/ext/picotcp/RFC/rfc1071.txt deleted file mode 100644 index 3b94108..0000000 --- a/ext/picotcp/RFC/rfc1071.txt +++ /dev/null @@ -1,1417 +0,0 @@ - - - - -Network Working Group R. Braden -Request for Comments: 1071 ISI - D. Borman - Cray Research - C. Partridge - BBN Laboratories - September 1988 - - - Computing the Internet Checksum - - -Status of This Memo - - This memo summarizes techniques and algorithms for efficiently - computing the Internet checksum. It is not a standard, but a set of - useful implementation techniques. Distribution of this memo is - unlimited. - -1. Introduction - - This memo discusses methods for efficiently computing the Internet - checksum that is used by the standard Internet protocols IP, UDP, and - TCP. - - An efficient checksum implementation is critical to good performance. - As advances in implementation techniques streamline the rest of the - protocol processing, the checksum computation becomes one of the - limiting factors on TCP performance, for example. It is usually - appropriate to carefully hand-craft the checksum routine, exploiting - every machine-dependent trick possible; a fraction of a microsecond - per TCP data byte can add up to a significant CPU time savings - overall. - - In outline, the Internet checksum algorithm is very simple: - - (1) Adjacent octets to be checksummed are paired to form 16-bit - integers, and the 1's complement sum of these 16-bit integers is - formed. - - (2) To generate a checksum, the checksum field itself is cleared, - the 16-bit 1's complement sum is computed over the octets - concerned, and the 1's complement of this sum is placed in the - checksum field. - - (3) To check a checksum, the 1's complement sum is computed over the - same set of octets, including the checksum field. If the result - is all 1 bits (-0 in 1's complement arithmetic), the check - succeeds. - - Suppose a checksum is to be computed over the sequence of octets - - - -Braden, Borman, & Partridge [Page 1] - -RFC 1071 Computing the Internet Checksum September 1988 - - - A, B, C, D, ... , Y, Z. Using the notation [a,b] for the 16-bit - integer a*256+b, where a and b are bytes, then the 16-bit 1's - complement sum of these bytes is given by one of the following: - - [A,B] +' [C,D] +' ... +' [Y,Z] [1] - - [A,B] +' [C,D] +' ... +' [Z,0] [2] - - where +' indicates 1's complement addition. These cases - correspond to an even or odd count of bytes, respectively. - - On a 2's complement machine, the 1's complement sum must be - computed by means of an "end around carry", i.e., any overflows - from the most significant bits are added into the least - significant bits. See the examples below. - - Section 2 explores the properties of this checksum that may be - exploited to speed its calculation. Section 3 contains some - numerical examples of the most important implementation - techniques. Finally, Section 4 includes examples of specific - algorithms for a variety of common CPU types. We are grateful - to Van Jacobson and Charley Kline for their contribution of - algorithms to this section. - - The properties of the Internet checksum were originally - discussed by Bill Plummer in IEN-45, entitled "Checksum Function - Design". Since IEN-45 has not been widely available, we include - it as an extended appendix to this RFC. - - 2. Calculating the Checksum - - This simple checksum has a number of wonderful mathematical - properties that may be exploited to speed its calculation, as we - will now discuss. - - - (A) Commutative and Associative - - As long as the even/odd assignment of bytes is respected, the - sum can be done in any order, and it can be arbitrarily split - into groups. - - For example, the sum [1] could be split into: - - ( [A,B] +' [C,D] +' ... +' [J,0] ) - - +' ( [0,K] +' ... +' [Y,Z] ) [3] - - - - - - - -Braden, Borman, & Partridge [Page 2] - -RFC 1071 Computing the Internet Checksum September 1988 - - - (B) Byte Order Independence - - The sum of 16-bit integers can be computed in either byte order. - Thus, if we calculate the swapped sum: - - [B,A] +' [D,C] +' ... +' [Z,Y] [4] - - the result is the same as [1], except the bytes are swapped in - the sum! To see why this is so, observe that in both orders the - carries are the same: from bit 15 to bit 0 and from bit 7 to bit - 8. In other words, consistently swapping bytes simply rotates - the bits within the sum, but does not affect their internal - ordering. - - Therefore, the sum may be calculated in exactly the same way - regardless of the byte order ("big-endian" or "little-endian") - of the underlaying hardware. For example, assume a "little- - endian" machine summing data that is stored in memory in network - ("big-endian") order. Fetching each 16-bit word will swap - bytes, resulting in the sum [4]; however, storing the result - back into memory will swap the sum back into network byte order. - - Byte swapping may also be used explicitly to handle boundary - alignment problems. For example, the second group in [3] can be - calculated without concern to its odd/even origin, as: - - [K,L] +' ... +' [Z,0] - - if this sum is byte-swapped before it is added to the first - group. See the example below. - - (C) Parallel Summation - - On machines that have word-sizes that are multiples of 16 bits, - it is possible to develop even more efficient implementations. - Because addition is associative, we do not have to sum the - integers in the order they appear in the message. Instead we - can add them in "parallel" by exploiting the larger word size. - - To compute the checksum in parallel, simply do a 1's complement - addition of the message using the native word size of the - machine. For example, on a 32-bit machine we can add 4 bytes at - a time: [A,B,C,D]+'... When the sum has been computed, we "fold" - the long sum into 16 bits by adding the 16-bit segments. Each - 16-bit addition may produce new end-around carries that must be - added. - - Furthermore, again the byte order does not matter; we could - instead sum 32-bit words: [D,C,B,A]+'... or [B,A,D,C]+'... and - then swap the bytes of the final 16-bit sum as necessary. See - the examples below. Any permutation is allowed that collects - - - -Braden, Borman, & Partridge [Page 3] - -RFC 1071 Computing the Internet Checksum September 1988 - - - all the even-numbered data bytes into one sum byte and the odd- - numbered data bytes into the other sum byte. - - - There are further coding techniques that can be exploited to speed up - the checksum calculation. - - (1) Deferred Carries - - Depending upon the machine, it may be more efficient to defer - adding end-around carries until the main summation loop is - finished. - - One approach is to sum 16-bit words in a 32-bit accumulator, so - the overflows build up in the high-order 16 bits. This approach - typically avoids a carry-sensing instruction but requires twice - as many additions as would adding 32-bit segments; which is - faster depends upon the detailed hardware architecture. - - (2) Unwinding Loops - - To reduce the loop overhead, it is often useful to "unwind" the - inner sum loop, replicating a series of addition commands within - one loop traversal. This technique often provides significant - savings, although it may complicate the logic of the program - considerably. - - (3) Combine with Data Copying - - Like checksumming, copying data from one memory location to - another involves per-byte overhead. In both cases, the - bottleneck is essentially the memory bus, i.e., how fast the - data can be fetched. On some machines (especially relatively - slow and simple micro-computers), overhead can be significantly - reduced by combining memory-to-memory copy and the checksumming, - fetching the data only once for both. - - (4) Incremental Update - - Finally, one can sometimes avoid recomputing the entire checksum - when one header field is updated. The best-known example is a - gateway changing the TTL field in the IP header, but there are - other examples (for example, when updating a source route). In - these cases it is possible to update the checksum without - scanning the message or datagram. - - To update the checksum, simply add the differences of the - sixteen bit integers that have been changed. To see why this - works, observe that every 16-bit integer has an additive inverse - and that addition is associative. From this it follows that - given the original value m, the new value m', and the old - - - -Braden, Borman, & Partridge [Page 4] - -RFC 1071 Computing the Internet Checksum September 1988 - - - checksum C, the new checksum C' is: - - C' = C + (-m) + m' = C + (m' - m) - - -3. Numerical Examples - - We now present explicit examples of calculating a simple 1's - complement sum on a 2's complement machine. The examples show the - same sum calculated byte by bye, by 16-bits words in normal and - swapped order, and 32 bits at a time in 3 different orders. All - numbers are in hex. - - Byte-by-byte "Normal" Swapped - Order Order - - Byte 0/1: 00 01 0001 0100 - Byte 2/3: f2 03 f203 03f2 - Byte 4/5: f4 f5 f4f5 f5f4 - Byte 6/7: f6 f7 f6f7 f7f6 - --- --- ----- ----- - Sum1: 2dc 1f0 2ddf0 1f2dc - - dc f0 ddf0 f2dc - Carrys: 1 2 2 1 - -- -- ---- ---- - Sum2: dd f2 ddf2 f2dd - - Final Swap: dd f2 ddf2 ddf2 - - - Byte 0/1/2/3: 0001f203 010003f2 03f20100 - Byte 4/5/6/7: f4f5f6f7 f5f4f7f6 f7f6f5f4 - -------- -------- -------- - Sum1: 0f4f7e8fa 0f6f4fbe8 0fbe8f6f4 - - Carries: 0 0 0 - - Top half: f4f7 f6f4 fbe8 - Bottom half: e8fa fbe8 f6f4 - ----- ----- ----- - Sum2: 1ddf1 1f2dc 1f2dc - - ddf1 f2dc f2dc - Carrys: 1 1 1 - ---- ---- ---- - Sum3: ddf2 f2dd f2dd - - Final Swap: ddf2 ddf2 ddf2 - - - - - -Braden, Borman, & Partridge [Page 5] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Finally, here an example of breaking the sum into two groups, with - the second group starting on a odd boundary: - - - Byte-by-byte Normal - Order - - Byte 0/1: 00 01 0001 - Byte 2/ : f2 (00) f200 - --- --- ----- - Sum1: f2 01 f201 - - Byte 4/5: 03 f4 03f4 - Byte 6/7: f5 f6 f5f6 - Byte 8/: f7 (00) f700 - --- --- ----- - Sum2: 1f0ea - - Sum2: f0ea - Carry: 1 - ----- - Sum3: f0eb - - Sum1: f201 - Sum3 byte swapped: ebf0 - ----- - Sum4: 1ddf1 - - Sum4: ddf1 - Carry: 1 - ----- - Sum5: ddf2 - - - - - - - - - - - - - - - - - - - - - - -Braden, Borman, & Partridge [Page 6] - -RFC 1071 Computing the Internet Checksum September 1988 - - -4. Implementation Examples - - In this section we show examples of Internet checksum implementation - algorithms that have been found to be efficient on a variety of - CPU's. In each case, we show the core of the algorithm, without - including environmental code (e.g., subroutine linkages) or special- - case code. - -4.1 "C" - - The following "C" code algorithm computes the checksum with an inner - loop that sums 16-bits at a time in a 32-bit accumulator. - - in 6 - { - /* Compute Internet Checksum for "count" bytes - * beginning at location "addr". - */ - register long sum = 0; - - while( count > 1 ) { - /* This is the inner loop */ - sum += * (unsigned short) addr++; - count -= 2; - } - - /* Add left-over byte, if any */ - if( count > 0 ) - sum += * (unsigned char *) addr; - - /* Fold 32-bit sum to 16 bits */ - while (sum>>16) - sum = (sum & 0xffff) + (sum >> 16); - - checksum = ~sum; - } - - - - - - - - - - - - - - - - - - -Braden, Borman, & Partridge [Page 7] - -RFC 1071 Computing the Internet Checksum September 1988 - - -4.2 Motorola 68020 - - The following algorithm is given in assembler language for a Motorola - 68020 chip. This algorithm performs the sum 32 bits at a time, and - unrolls the loop with 16 replications. For clarity, we have omitted - the logic to add the last fullword when the length is not a multiple - of 4. The result is left in register d0. - - With a 20MHz clock, this routine was measured at 134 usec/kB summing - random data. This algorithm was developed by Van Jacobson. - - - movl d1,d2 - lsrl #6,d1 | count/64 = # loop traversals - andl #0x3c,d2 | Then find fractions of a chunk - negl d2 - andb #0xf,cc | Clear X (extended carry flag) - - jmp pc@(2$-.-2:b,d2) | Jump into loop - - 1$: | Begin inner loop... - - movl a0@+,d2 | Fetch 32-bit word - addxl d2,d0 | Add word + previous carry - movl a0@+,d2 | Fetch 32-bit word - addxl d2,d0 | Add word + previous carry - - | ... 14 more replications - 2$: - dbra d1,1$ | (NB- dbra doesn't affect X) - - movl d0,d1 | Fold 32 bit sum to 16 bits - swap d1 | (NB- swap doesn't affect X) - addxw d1,d0 - jcc 3$ - addw #1,d0 - 3$: - andl #0xffff,d0 - - - - - - - - - - - - - - - - -Braden, Borman, & Partridge [Page 8] - -RFC 1071 Computing the Internet Checksum September 1988 - - -4.3 Cray - - The following example, in assembler language for a Cray CPU, was - contributed by Charley Kline. It implements the checksum calculation - as a vector operation, summing up to 512 bytes at a time with a basic - summation unit of 32 bits. This example omits many details having to - do with short blocks, for clarity. - - Register A1 holds the address of a 512-byte block of memory to - checksum. First two copies of the data are loaded into two vector - registers. One is vector-shifted right 32 bits, while the other is - vector-ANDed with a 32 bit mask. Then the two vectors are added - together. Since all these operations chain, it produces one result - per clock cycle. Then it collapses the result vector in a loop that - adds each element to a scalar register. Finally, the end-around - carry is performed and the result is folded to 16-bits. - - EBM - A0 A1 - VL 64 use full vectors - S1 <32 form 32-bit mask from the right. - A2 32 - V1 ,A0,1 load packet into V1 - V2 S1&V1 Form right-hand 32-bits in V2. - V3 V1>A2 Form left-hand 32-bits in V3. - V1 V2+V3 Add the two together. - A2 63 Prepare to collapse into a scalar. - S1 0 - S4 <16 Form 16-bit mask from the right. - A4 16 - CK$LOOP S2 V1,A2 - A2 A2-1 - A0 A2 - S1 S1+S2 - JAN CK$LOOP - S2 S1&S4 Form right-hand 16-bits in S2 - S1 S1>A4 Form left-hand 16-bits in S1 - S1 S1+S2 - S2 S1&S4 Form right-hand 16-bits in S2 - S1 S1>A4 Form left-hand 16-bits in S1 - S1 S1+S2 - S1 #S1 Take one's complement - CMR At this point, S1 contains the checksum. - - - - - - - - - - - -Braden, Borman, & Partridge [Page 9] - -RFC 1071 Computing the Internet Checksum September 1988 - - -4.4 IBM 370 - - The following example, in assembler language for an IBM 370 CPU, sums - the data 4 bytes at a time. For clarity, we have omitted the logic - to add the last fullword when the length is not a multiple of 4, and - to reverse the bytes when necessary. The result is left in register - RCARRY. - - This code has been timed on an IBM 3090 CPU at 27 usec/KB when - summing all one bits. This time is reduced to 24.3 usec/KB if the - trouble is taken to word-align the addends (requiring special cases - at both the beginning and the end, and byte-swapping when necessary - to compensate for starting on an odd byte). - - * Registers RADDR and RCOUNT contain the address and length of - * the block to be checksummed. - * - * (RCARRY, RSUM) must be an even/odd register pair. - * (RCOUNT, RMOD) must be an even/odd register pair. - * - CHECKSUM SR RSUM,RSUM Clear working registers. - SR RCARRY,RCARRY - LA RONE,1 Set up constant 1. - * - SRDA RCOUNT,6 Count/64 to RCOUNT. - AR RCOUNT,RONE +1 = # times in loop. - SRL RMOD,26 Size of partial chunk to RMOD. - AR RADDR,R3 Adjust addr to compensate for - S RADDR,=F(64) jumping into the loop. - SRL RMOD,1 (RMOD/4)*2 is halfword index. - LH RMOD,DOPEVEC9(RMOD) Use magic dope-vector for offset, - B LOOP(RMOD) and jump into the loop... - * - * Inner loop: - * - LOOP AL RSUM,0(,RADDR) Add Logical fullword - BC 12,*+6 Branch if no carry - AR RCARRY,RONE Add 1 end-around - AL RSUM,4(,RADDR) Add Logical fullword - BC 12,*+6 Branch if no carry - AR RCARRY,RONE Add 1 end-around - * - * ... 14 more replications ... - * - A RADDR,=F'64' Increment address ptr - BCT RCOUNT,LOOP Branch on Count - * - * Add Carries into sum, and fold to 16 bits - * - ALR RCARRY,RSUM Add SUM and CARRY words - BC 12,*+6 and take care of carry - - - -Braden, Borman, & Partridge [Page 10] - -RFC 1071 Computing the Internet Checksum September 1988 - - - AR RCARRY,RONE - SRDL RCARRY,16 Fold 32-bit sum into - SRL RSUM,16 16-bits - ALR RCARRY,RSUM - C RCARRY,=X'0000FFFF' and take care of any - BNH DONE last carry - S RCARRY,=X'0000FFFF' - DONE X RCARRY,=X'0000FFFF' 1's complement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Braden, Borman, & Partridge [Page 11] - -RFC 1071 Computing the Internet Checksum September 1988 - - - IEN 45 - Section 2.4.4.5 - - - - - - - - - - - - - - - - - TCP Checksum Function Design - - - - William W. Plummer - - - Bolt Beranek and Newman, Inc. - 50 Moulton Street - Cambridge MA 02138 - - - 5 June 1978 - - - - - - - - - - - - - - - - - - - - - - - -Braden, Borman, & Partridge [Page 12] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - 1. Introduction - - Checksums are included in packets in order that errors - encountered during transmission may be detected. For Internet - protocols such as TCP [1,9] this is especially important because - packets may have to cross wireless networks such as the Packet - Radio Network [2] and Atlantic Satellite Network [3] where - packets may be corrupted. Internet protocols (e.g., those for - real time speech transmission) can tolerate a certain level of - transmission errors and forward error correction techniques or - possibly no checksum at all might be better. The focus in this - paper is on checksum functions for protocols such as TCP where - the required reliable delivery is achieved by retransmission. - - Even if the checksum appears good on a message which has been - received, the message may still contain an undetected error. The - probability of this is bounded by 2**(-C) where C is the number - of checksum bits. Errors can arise from hardware (and software) - malfunctions as well as transmission errors. Hardware induced - errors are usually manifested in certain well known ways and it - is desirable to account for this in the design of the checksum - function. Ideally no error of the "common hardware failure" type - would go undetected. - - An example of a failure that the current checksum function - handles successfully is picking up a bit in the network interface - (or I/O buss, memory channel, etc.). This will always render the - checksum bad. For an example of how the current function is - inadequate, assume that a control signal stops functioning in the - network interface and the interface stores zeros in place of the - real data. These "all zero" messages appear to have valid - checksums. Noise on the "There's Your Bit" line of the ARPANET - Interface [4] may go undetected because the extra bits input may - cause the checksum to be perturbed (i.e., shifted) in the same - way as the data was. - - Although messages containing undetected errors will occasionally - be passed to higher levels of protocol, it is likely that they - will not make sense at that level. In the case of TCP most such - messages will be ignored, but some could cause a connection to be - aborted. Garbled data could be viewed as a problem for a layer - of protocol above TCP which itself may have a checksuming scheme. - - This paper is the first step in design of a new checksum function - for TCP and some other Internet protocols. Several useful - properties of the current function are identified. If possible - - - 1 - - - - -Braden, Borman, & Partridge [Page 13] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - these should be retained in any new function. A number of - plausible checksum schemes are investigated. Of these only the - "product code" seems to be simple enough for consideration. - - 2. The Current TCP Checksum Function - - The current function is oriented towards sixteen-bit machines - such as the PDP-11 but can be computed easily on other machines - (e.g., PDP-10). A packet is thought of as a string of 16-bit - bytes and the checksum function is the one's complement sum (add - with end-around carry) of those bytes. It is the one's - complement of this sum which is stored in the checksum field of - the TCP header. Before computing the checksum value, the sender - places a zero in the checksum field of the packet. If the - checksum value computed by a receiver of the packet is zero, the - packet is assumed to be valid. This is a consequence of the - "negative" number in the checksum field exactly cancelling the - contribution of the rest of the packet. - - Ignoring the difficulty of actually evaluating the checksum - function for a given packet, the way of using the checksum - described above is quite simple, but it assumes some properties - of the checksum operator (one's complement addition, "+" in what - follows): - - (P1) + is commutative. Thus, the order in which - the 16-bit bytes are "added" together is - unimportant. - - (P2) + has at least one identity element (The - current function has two: +0 and -0). This - allows the sender to compute the checksum - function by placing a zero in the packet checksum - field before computing the value. - - (P3) + has an inverse. Thus, the receiver may - evaluate the checksum function and expect a zero. - - (P4) + is associative, allowing the checksum field - to be anywhere in the packet and the 16-bit bytes - to be scanned sequentially. - - Mathematically, these properties of the binary operation "+" over - the set of 16-bit numbers forms an Abelian group [5]. Of course, - there are many Abelian groups but not all would be satisfactory - for use as checksum operators. (Another operator readily - - - 2 - - - - -Braden, Borman, & Partridge [Page 14] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - available in the PDP-11 instruction set that has all of these - properties is exclusive-OR, but XOR is unsatisfactory for other - reasons.) - - Albeit imprecise, another property which must be preserved in any - future checksum scheme is: - - (P5) + is fast to compute on a variety of machines - with limited storage requirements. - - The current function is quite good in this respect. On the - PDP-11 the inner loop looks like: - - LOOP: ADD (R1)+,R0 ; Add the next 16-bit byte - ADC R0 ; Make carry be end-around - SOB R2,LOOP ; Loop over entire packet. - - ( 4 memory cycles per 16-bit byte ) - - On the PDP-10 properties P1-4 are exploited further and two - 16-bit bytes per loop are processed: - - LOOP: ILDB THIS,PTR ; Get 2 16-bit bytes - ADD SUM,THIS ; Add into current sum - JUMPGE SUM,CHKSU2 ; Jump if fewer than 8 carries - LDB THIS,[POINT 20,SUM,19] ; Get left 16 and carries - ANDI SUM,177777 ; Save just low 16 here - ADD SUM,THIS ; Fold in carries - CHKSU2: SOJG COUNT,LOOP ; Loop over entire packet - - ( 3.1 memory cycles per 16-bit byte ) - - The "extra" instruction in the loops above are required to - convert the two's complement ADD instruction(s) into a one's - complement add by making the carries be end-around. One's - complement arithmetic is better than two's complement because it - is equally sensitive to errors in all bit positions. If two's - complement addition were used, an even number of 1's could be - dropped (or picked up) in the most significant bit channel - without affecting the value of the checksum. It is just this - property that makes some sort of addition preferable to a simple - exclusive-OR which is frequently used but permits an even number - of drops (pick ups) in any bit channel. RIM10B paper tape format - used on PDP-10s [10] uses two's complement add because space for - the loader program is extremely limited. - - - 3 - - - - - -Braden, Borman, & Partridge [Page 15] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - Another property of the current checksum scheme is: - - (P6) Adding the checksum to a packet does not change - the information bytes. Peterson [6] calls this a - "systematic" code. - - This property allows intermediate computers such as gateway - machines to act on fields (i.e., the Internet Destination - Address) without having to first decode the packet. Cyclical - Redundancy Checks used for error correction are not systematic - either. However, most applications of CRCs tend to emphasize - error detection rather than correction and consequently can send - the message unchanged, with the CRC check bits being appended to - the end. The 24-bit CRC used by ARPANET IMPs and Very Distant - Host Interfaces [4] and the ANSI standards for 800 and 6250 bits - per inch magnetic tapes (described in [11]) use this mode. - - Note that the operation of higher level protocols are not (by - design) affected by anything that may be done by a gateway acting - on possibly invalid packets. It is permissible for gateways to - validate the checksum on incoming packets, but in general - gateways will not know how to do this if the checksum is a - protocol-specific feature. - - A final property of the current checksum scheme which is actually - a consequence of P1 and P4 is: - - (P7) The checksum may be incrementally modified. - - This property permits an intermediate gateway to add information - to a packet, for instance a timestamp, and "add" an appropriate - change to the checksum field of the packet. Note that the - checksum will still be end-to-end since it was not fully - recomputed. - - 3. Product Codes - - Certain "product codes" are potentially useful for checksuming - purposes. The following is a brief description of product codes - in the context of TCP. More general treatment can be found in - Avizienis [7] and probably other more recent works. - - The basic concept of this coding is that the message (packet) to - be sent is formed by transforming the original source message and - adding some "check" bits. By reading this and applying a - (possibly different) transformation, a receiver can reconstruct - - - 4 - - - - -Braden, Borman, & Partridge [Page 16] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - the original message and determine if it has been corrupted - during transmission. - - Mo Ms Mr - - ----- ----- ----- - | A | code | 7 | decode | A | - | B | ==> | 1 | ==> | B | - | C | | 4 | | C | - ----- |...| ----- - | 2 | check plus "valid" flag - ----- info - - Original Sent Reconstructed - - With product codes the transformation is Ms = K * Mo . That is, - the message sent is simply the product of the original message - Mo and some well known constant K . To decode, the received - Ms is divided by K which will yield Mr as the quotient and - 0 as the remainder if Mr is to be considered the same as Mo . - - The first problem is selecting a "good" value for K, the "check - factor". K must be relatively prime to the base chosen to - express the message. (Example: Binary messages with K - incorrectly chosen to be 8. This means that Ms looks exactly - like Mo except that three zeros have been appended. The only - way the message could look bad to a receiver dividing by 8 is if - the error occurred in one of those three bits.) - - For TCP the base R will be chosen to be 2**16. That is, every - 16-bit byte (word on the PDP-11) will be considered as a digit of - a big number and that number is the message. Thus, - - Mo = SIGMA [ Bi * (R**i)] , Bi is i-th byte - i=0 to N - - Ms = K * Mo - - Corrupting a single digit of Ms will yield Ms' = Ms +or- - C*(R**j) for some radix position j . The receiver will compute - Ms'/K = Mo +or- C(R**j)/K. Since R and K are relatively prime, - C*(R**j) cannot be any exact multiple of K. Therefore, the - division will result in a non-zero remainder which indicates that - Ms' is a corrupted version of Ms. As will be seen, a good - choice for K is (R**b - 1), for some b which is the "check - length" which controls the degree of detection to be had for - - - 5 - - - - -Braden, Borman, & Partridge [Page 17] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - burst errors which affect a string of digits (i.e., 16-bit bytes) - in the message. In fact b will be chosen to be 1, so K will - be 2**16 - 1 so that arithmetic operations will be simple. This - means that all bursts of 15 or fewer bits will be detected. - According to [7] this choice for b results in the following - expression for the fraction of undetected weight 2 errors: - - f = 16(k-1)/[32(16k-3) + (6/k)] where k is the message length. - - For large messages f approaches 3.125 per cent as k goes to - infinity. - - Multiple precision multiplication and division are normally quite - complex operations, especially on small machines which typically - lack even single precision multiply and divide operations. The - exception to this is exactly the case being dealt with here -- - the factor is 2**16 - 1 on machines with a word length of 16 - bits. The reason for this is due to the following identity: - - Q*(R**j) = Q, mod (R-1) 0 <= Q < R - - That is, any digit Q in the selected radix (0, 1, ... R-1) - multiplied by any power of the radix will have a remainder of Q - when divided by the radix minus 1. - - Example: In decimal R = 10. Pick Q = 6. - - 6 = 0 * 9 + 6 = 6, mod 9 - 60 = 6 * 9 + 6 = 6, mod 9 - 600 = 66 * 9 + 6 = 6, mod 9 etc. - - More to the point, rem(31415/9) = rem((30000+1000+400+10+5)/9) - = (3 mod 9) + (1 mod 9) + (4 mod 9) + (1 mod 9) + (5 mod 9) - = (3+1+4+1+5) mod 9 - = 14 mod 9 - = 5 - - So, the remainder of a number divided by the radix minus one can - be found by simply summing the digits of the number. Since the - radix in the TCP case has been chosen to be 2**16 and the check - factor is 2**16 - 1, a message can quickly be checked by summing - all of the 16-bit words (on a PDP-11), with carries being - end-around. If zero is the result, the message can be considered - valid. Thus, checking a product coded message is exactly the - same complexity as with the current TCP checksum! - - - 6 - - - - - -Braden, Borman, & Partridge [Page 18] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - In order to form Ms, the sender must multiply the multiple - precision "number" Mo by 2**16 - 1. Or, Ms = (2**16)Mo - Mo. - This is performed by shifting Mo one whole word's worth of - precision and subtracting Mo. Since carries must propagate - between digits, but it is only the current digit which is of - interest, one's complement arithmetic is used. - - (2**16)Mo = Mo0 + Mo1 + Mo2 + ... + MoX + 0 - - Mo = - ( Mo0 + Mo1 + ......... + MoX) - --------- ---------------------------------- - Ms = Ms0 + Ms1 + ... - MoX - - A loop which implements this function on a PDP-11 might look - like: - LOOP: MOV -2(R2),R0 ; Next byte of (2**16)Mo - SBC R0 ; Propagate carries from last SUB - SUB (R2)+,R0 ; Subtract byte of Mo - MOV R0,(R3)+ ; Store in Ms - SOB R1,LOOP ; Loop over entire message - ; 8 memory cycles per 16-bit byte - - Note that the coding procedure is not done in-place since it is - not systematic. In general the original copy, Mo, will have to - be retained by the sender for retransmission purposes and - therefore must remain readable. Thus the MOV R0,(R3)+ is - required which accounts for 2 of the 8 memory cycles per loop. - - The coding procedure will add exactly one 16-bit word to the - message since Ms < (2**16)Mo . This additional 16 bits will be - at the tail of the message, but may be moved into the defined - location in the TCP header immediately before transmission. The - receiver will have to undo this to put Ms back into standard - format before decoding the message. - - The code in the receiver for fully decoding the message may be - inferred by observing that any word in Ms contains the - difference between two successive words of Mo minus the carries - from the previous word, and the low order word contains minus the - low word of Mo. So the low order (i.e., rightmost) word of Mr is - just the negative of the low order byte of Ms. The next word of - Mr is the next word of Ms plus the just computed word of Mr - plus the carry from that previous computation. - - A slight refinement of the procedure is required in order to - protect against an all-zero message passing to the destination. - This will appear to have a valid checksum because Ms'/K = 0/K - - - 7 - - - - -Braden, Borman, & Partridge [Page 19] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - = 0 with 0 remainder. The refinement is to make the coding be - Ms = K*Mo + C where C is some arbitrary, well-known constant. - Adding this constant requires a second pass over the message, but - this will typically be very short since it can stop as soon as - carries stop propagating. Chosing C = 1 is sufficient in most - cases. - - The product code checksum must be evaluated in terms of the - desired properties P1 - P7. It has been shown that a factor of - two more machine cycles are consumed in computing or verifying a - product code checksum (P5 satisfied?). - - Although the code is not systematic, the checksum can be verified - quickly without decoding the message. If the Internet - Destination Address is located at the least significant end of - the packet (where the product code computation begins) then it is - possible for a gateway to decode only enough of the message to - see this field without having to decode the entire message. - Thus, P6 is at least partially satisfied. The algebraic - properties P1 through P4 are not satisfied, but only a small - amount of computation is needed to account for this -- the - message needs to be reformatted as previously mentioned. - - P7 is satisfied since the product code checksum can be - incrementally updated to account for an added word, although the - procedure is somewhat involved. Imagine that the original - message has two halves, H1 and H2. Thus, Mo = H1*(R**j) + H2. - The timestamp word is to be inserted between these halves to form - a modified Mo' = H1*(R**(j+1)) + T*(R**j) + H2. Since K has - been chosen to be R-1, the transmitted message Ms' = Mo'(R-1). - Then, - - Ms' = Ms*R + T(R-1)(R**j) + P2((R-1)**2) - - = Ms*R + T*(R**(j+1)) + T*(R**j) + P2*(R**2) - 2*P2*R - P2 - - Recalling that R is 2**16, the word size on the PDP-11, - multiplying by R means copying down one word in memory. So, - the first term of Ms' is simply the unmodified message copied - down one word. The next term is the new data T added into the - Ms' being formed beginning at the (j+1)th word. The addition is - fairly easy here since after adding in T all that is left is - propagating the carry, and that can stop as soon as no carry is - produced. The other terms can be handle similarly. - - - 8 - - - - - - -Braden, Borman, & Partridge [Page 20] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - 4. More Complicated Codes - - There exists a wealth of theory on error detecting and correcting - codes. Peterson [6] is an excellent reference. Most of these - "CRC" schemes are designed to be implemented using a shift - register with a feedback network composed of exclusive-ORs. - Simulating such a logic circuit with a program would be too slow - to be useful unless some programming trick is discovered. - - One such trick has been proposed by Kirstein [8]. Basically, a - few bits (four or eight) of the current shift register state are - combined with bits from the input stream (from Mo) and the result - is used as an index to a table which yields the new shift - register state and, if the code is not systematic, bits for the - output stream (Ms). A trial coding of an especially "good" CRC - function using four-bit bytes showed showed this technique to be - about four times as slow as the current checksum function. This - was true for both the PDP-10 and PDP-11 machines. Of the - desirable properties listed above, CRC schemes satisfy only P3 - (It has an inverse.), and P6 (It is systematic.). Placement of - the checksum field in the packet is critical and the CRC cannot - be incrementally modified. - - Although the bulk of coding theory deals with binary codes, most - of the theory works if the alphabet contains q symbols, where - q is a power of a prime number. For instance q taken as 2**16 - should make a great deal of the theory useful on a word-by-word - basis. - - 5. Outboard Processing - - When a function such as computing an involved checksum requires - extensive processing, one solution is to put that processing into - an outboard processor. In this way "encode message" and "decode - message" become single instructions which do not tax the main - host processor. The Digital Equipment Corporation VAX/780 - computer is equipped with special hardware for generating and - checking CRCs [13]. In general this is not a very good solution - since such a processor must be constructed for every different - host machine which uses TCP messages. - - It is conceivable that the gateway functions for a large host may - be performed entirely in an "Internet Frontend Machine". This - machine would be responsible for forwarding packets received - - - 9 - - - - - - -Braden, Borman, & Partridge [Page 21] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - either from the network(s) or from the Internet protocol modules - in the connected host, and for reassembling Internet fragments - into segments and passing these to the host. Another capability - of this machine would be to check the checksum so that the - segments given to the host are known to be valid at the time they - leave the frontend. Since computer cycles are assumed to be both - inexpensive and available in the frontend, this seems reasonable. - - The problem with attempting to validate checksums in the frontend - is that it destroys the end-to-end character of the checksum. If - anything, this is the most powerful feature of the TCP checksum! - There is a way to make the host-to-frontend link be covered by - the end-to-end checksum. A separate, small protocol must be - developed to cover this link. After having validated an incoming - packet from the network, the frontend would pass it to the host - saying "here is an Internet segment for you. Call it #123". The - host would save this segment, and send a copy back to the - frontend saying, "Here is what you gave me as #123. Is it OK?". - The frontend would then do a word-by-word comparison with the - first transmission, and tell the host either "Here is #123 - again", or "You did indeed receive #123 properly. Release it to - the appropriate module for further processing." - - The headers on the messages crossing the host-frontend link would - most likely be covered by a fairly strong checksum so that - information like which function is being performed and the - message reference numbers are reliable. These headers would be - quite short, maybe only sixteen bits, so the checksum could be - quite strong. The bulk of the message would not be checksumed of - course. - The reason this scheme reduces the computing burden on the host - is that all that is required in order to validate the message - using the end-to-end checksum is to send it back to the frontend - machine. In the case of the PDP-10, this requires only 0.5 - memory cycles per 16-bit byte of Internet message, and only a few - processor cycles to setup the required transfers. - - 6. Conclusions - - There is an ordering of checksum functions: first and simplest is - none at all which provides no error detection or correction. - Second, is sending a constant which is checked by the receiver. - This also is extremely weak. Third, the exclusive-OR of the data - may be sent. XOR takes the minimal amount of computer time to - generate and check, but is not a good checksum. A two's - complement sum of the data is somewhat better and takes no more - - - 10 - - - - -Braden, Borman, & Partridge [Page 22] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - computer time to compute. Fifth, is the one's complement sum - which is what is currently used by TCP. It is slightly more - expensive in terms of computer time. The next step is a product - code. The product code is strongly related to one's complement - sum, takes still more computer time to use, provides a bit more - protection against common hardware failures, but has some - objectionable properties. Next is a genuine CRC polynomial code, - used for checking purposes only. This is very expensive for a - program to implement. Finally, a full CRC error correcting and - detecting scheme may be used. - - For TCP and Internet applications the product code scheme is - viable. It suffers mainly in that messages must be (at least - partially) decoded by intermediate gateways in order that they - can be forwarded. Should product codes not be chosen as an - improved checksum, some slight modification to the existing - scheme might be possible. For instance the "add and rotate" - function used for paper tape by the PDP-6/10 group at the - Artificial Intelligence Laboratory at M.I.T. Project MAC [12] - could be useful if it can be proved that it is better than the - current scheme and that it can be computed efficiently on a - variety of machines. - - - - - - - - - - - - - - - - - - - - - - - 11 - - - - - - - - -Braden, Borman, & Partridge [Page 23] - -RFC 1071 Computing the Internet Checksum September 1988 - - - Internet Experiment Note 45 5 June 1978 - TCP Checksum Function Design William W. Plummer - - References - - [1] Cerf, V.G. and Kahn, Robert E., "A Protocol for Packet Network - Communications," IEEE Transactions on Communications, vol. - COM-22, No. 5, May 1974. - - [2] Kahn, Robert E., "The Organization of Computer Resources into - a Packet Radio Network", IEEE Transactions on Communications, - vol. COM-25, no. 1, pp. 169-178, January 1977. - - [3] Jacobs, Irwin, et al., "CPODA - A Demand Assignment Protocol - for SatNet", Fifth Data Communications Symposium, September - 27-9, 1977, Snowbird, Utah - - [4] Bolt Beranek and Newman, Inc. "Specifications for the - Interconnection of a Host and an IMP", Report 1822, January - 1976 edition. - - [5] Dean, Richard A., "Elements of Abstract Algebra", John Wyley - and Sons, Inc., 1966 - - [6] Peterson, W. Wesley, "Error Correcting Codes", M.I.T. Press - Cambridge MA, 4th edition, 1968. - - [7] Avizienis, Algirdas, "A Study of the Effectiveness of Fault- - Detecting Codes for Binary Arithmetic", Jet Propulsion - Laboratory Technical Report No. 32-711, September 1, 1965. - - [8] Kirstein, Peter, private communication - - [9] Cerf, V. G. and Postel, Jonathan B., "Specification of - Internetwork Transmission Control Program Version 3", - University of Southern California Information Sciences - Institute, January 1978. - - [10] Digital Equipment Corporation, "PDP-10 Reference Handbook", - 1970, pp. 114-5. - - [11] Swanson, Robert, "Understanding Cyclic Redundancy Codes", - Computer Design, November, 1975, pp. 93-99. - - [12] Clements, Robert C., private communication. - - [13] Conklin, Peter F., and Rodgers, David P., "Advanced - Minicomputer Designed by Team Evaluation of Hardware/Software - Tradeoffs", Computer Design, April 1978, pp. 136-7. - - - 12 - - - - -Braden, Borman, & Partridge [Page 24] - diff --git a/ext/picotcp/RFC/rfc1072.txt b/ext/picotcp/RFC/rfc1072.txt deleted file mode 100644 index 6ed8d5b..0000000 --- a/ext/picotcp/RFC/rfc1072.txt +++ /dev/null @@ -1,893 +0,0 @@ -Network Working Group V. Jacobson -Request for Comments: 1072 LBL - R. Braden - ISI - October 1988 - - - TCP Extensions for Long-Delay Paths - - -Status of This Memo - - This memo proposes a set of extensions to the TCP protocol to provide - efficient operation over a path with a high bandwidth*delay product. - These extensions are not proposed as an Internet standard at this - time. Instead, they are intended as a basis for further - experimentation and research on transport protocol performance. - Distribution of this memo is unlimited. - -1. INTRODUCTION - - Recent work on TCP performance has shown that TCP can work well over - a variety of Internet paths, ranging from 800 Mbit/sec I/O channels - to 300 bit/sec dial-up modems [Jacobson88]. However, there is still - a fundamental TCP performance bottleneck for one transmission regime: - paths with high bandwidth and long round-trip delays. The - significant parameter is the product of bandwidth (bits per second) - and round-trip delay (RTT in seconds); this product is the number of - bits it takes to "fill the pipe", i.e., the amount of unacknowledged - data that TCP must handle in order to keep the pipeline full. TCP - performance problems arise when this product is large, e.g., - significantly exceeds 10**5 bits. We will refer to an Internet path - operating in this region as a "long, fat pipe", and a network - containing this path as an "LFN" (pronounced "elephan(t)"). - - High-capacity packet satellite channels (e.g., DARPA's Wideband Net) - are LFN's. For example, a T1-speed satellite channel has a - bandwidth*delay product of 10**6 bits or more; this corresponds to - 100 outstanding TCP segments of 1200 bytes each! Proposed future - terrestrial fiber-optical paths will also fall into the LFN class; - for example, a cross-country delay of 30 ms at a DS3 bandwidth - (45Mbps) also exceeds 10**6 bits. - - Clever algorithms alone will not give us good TCP performance over - LFN's; it will be necessary to actually extend the protocol. This - RFC proposes a set of TCP extensions for this purpose. - - There are three fundamental problems with the current TCP over LFN - - - -Jacobson & Braden [Page 1] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - paths: - - - (1) Window Size Limitation - - The TCP header uses a 16 bit field to report the receive window - size to the sender. Therefore, the largest window that can be - used is 2**16 = 65K bytes. (In practice, some TCP - implementations will "break" for windows exceeding 2**15, - because of their failure to do unsigned arithmetic). - - To circumvent this problem, we propose a new TCP option to allow - windows larger than 2**16. This option will define an implicit - scale factor, to be used to multiply the window size value found - in a TCP header to obtain the true window size. - - - (2) Cumulative Acknowledgments - - Any packet losses in an LFN can have a catastrophic effect on - throughput. This effect is exaggerated by the simple cumulative - acknowledgment of TCP. Whenever a segment is lost, the - transmitting TCP will (eventually) time out and retransmit the - missing segment. However, the sending TCP has no information - about segments that may have reached the receiver and been - queued because they were not at the left window edge, so it may - be forced to retransmit these segments unnecessarily. - - We propose a TCP extension to implement selective - acknowledgements. By sending selective acknowledgments, the - receiver of data can inform the sender about all segments that - have arrived successfully, so the sender need retransmit only - the segments that have actually been lost. - - Selective acknowledgments have been included in a number of - experimental Internet protocols -- VMTP [Cheriton88], NETBLT - [Clark87], and RDP [Velten84]. There is some empirical evidence - in favor of selective acknowledgments -- simple experiments with - RDP have shown that disabling the selective acknowlegment - facility greatly increases the number of retransmitted segments - over a lossy, high-delay Internet path [Partridge87]. A - simulation study of a simple form of selective acknowledgments - added to the ISO transport protocol TP4 also showed promise of - performance improvement [NBS85]. - - - - - - - -Jacobson & Braden [Page 2] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - (3) Round Trip Timing - - TCP implements reliable data delivery by measuring the RTT, - i.e., the time interval between sending a segment and receiving - an acknowledgment for it, and retransmitting any segments that - are not acknowledged within some small multiple of the average - RTT. Experience has shown that accurate, current RTT estimates - are necessary to adapt to changing traffic conditions and, - without them, a busy network is subject to an instability known - as "congestion collapse" [Nagle84]. - - In part because TCP segments may be repacketized upon - retransmission, and in part because of complications due to the - cumulative TCP acknowledgement, measuring a segments's RTT may - involve a non-trivial amount of computation in some - implementations. To minimize this computation, some - implementations time only one segment per window. While this - yields an adequate approximation to the RTT for small windows - (e.g., a 4 to 8 segment Arpanet window), for an LFN (e.g., 100 - segment Wideband Network windows) it results in an unacceptably - poor RTT estimate. - - In the presence of errors, the problem becomes worse. Zhang - [Zhang86], Jain [Jain86] and Karn [Karn87] have shown that it is - not possible to accumulate reliable RTT estimates if - retransmitted segments are included in the estimate. Since a - full window of data will have been transmitted prior to a - retransmission, all of the segments in that window will have to - be ACKed before the next RTT sample can be taken. This means at - least an additional window's worth of time between RTT - measurements and, as the error rate approaches one per window of - data (e.g., 10**-6 errors per bit for the Wideband Net), it - becomes effectively impossible to obtain an RTT measurement. - - We propose a TCP "echo" option that allows each segment to carry - its own timestamp. This will allow every segment, including - retransmissions, to be timed at negligible computational cost. - - - In designing new TCP options, we must pay careful attention to - interoperability with existing implementations. The only TCP option - defined to date is an "initial option", i.e., it may appear only on a - SYN segment. It is likely that most implementations will properly - ignore any options in the SYN segment that they do not understand, so - new initial options should not cause a problem. On the other hand, - we fear that receiving unexpected non-initial options may cause some - TCP's to crash. - - - - -Jacobson & Braden [Page 3] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - Therefore, in each of the extensions we propose, non-initial options - may be sent only if an exchange of initial options has indicated that - both sides understand the extension. This approach will also allow a - TCP to determine when the connection opens how big a TCP header it - will be sending. - -2. TCP WINDOW SCALE OPTION - - The obvious way to implement a window scale factor would be to define - a new TCP option that could be included in any segment specifying a - window. The receiver would include it in every acknowledgment - segment, and the sender would interpret it. Unfortunately, this - simple approach would not work. The sender must reliably know the - receiver's current scale factor, but a TCP option in an - acknowledgement segment will not be delivered reliably (unless the - ACK happens to be piggy-backed on data). - - However, SYN segments are always sent reliably, suggesting that each - side may communicate its window scale factor in an initial TCP - option. This approach has a disadvantage: the scale must be - established when the connection is opened, and cannot be changed - thereafter. However, other alternatives would be much more - complicated, and we therefore propose a new initial option called - Window Scale. - -2.1 Window Scale Option - - This three-byte option may be sent in a SYN segment by a TCP (1) - to indicate that it is prepared to do both send and receive window - scaling, and (2) to communicate a scale factor to be applied to - its receive window. The scale factor is encoded logarithmically, - as a power of 2 (presumably to be implemented by binary shifts). - - Note: the window in the SYN segment itself is never scaled. - - TCP Window Scale Option: - - Kind: 3 - - +---------+---------+---------+ - | Kind=3 |Length=3 |shift.cnt| - +---------+---------+---------+ - - Here shift.cnt is the number of bits by which the receiver right- - shifts the true receive-window value, to scale it into a 16-bit - value to be sent in TCP header (this scaling is explained below). - The value shift.cnt may be zero (offering to scale, while applying - a scale factor of 1 to the receive window). - - - -Jacobson & Braden [Page 4] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - This option is an offer, not a promise; both sides must send - Window Scale options in their SYN segments to enable window - scaling in either direction. - -2.2 Using the Window Scale Option - - A model implementation of window scaling is as follows, using the - notation of RFC-793 [Postel81]: - - * The send-window (SND.WND) and receive-window (RCV.WND) sizes - in the connection state block and in all sequence space - calculations are expanded from 16 to 32 bits. - - * Two window shift counts are added to the connection state: - snd.scale and rcv.scale. These are shift counts to be - applied to the incoming and outgoing windows, respectively. - The precise algorithm is shown below. - - * All outgoing SYN segments are sent with the Window Scale - option, containing a value shift.cnt = R that the TCP would - like to use for its receive window. - - * Snd.scale and rcv.scale are initialized to zero, and are - changed only during processing of a received SYN segment. If - the SYN segment contains a Window Scale option with shift.cnt - = S, set snd.scale to S and set rcv.scale to R; otherwise, - both snd.scale and rcv.scale are left at zero. - - * The window field (SEG.WND) in the header of every incoming - segment, with the exception of SYN segments, will be left- - shifted by snd.scale bits before updating SND.WND: - - SND.WND = SEG.WND << snd.scale - - (assuming the other conditions of RFC793 are met, and using - the "C" notation "<<" for left-shift). - - * The window field (SEG.WND) of every outgoing segment, with - the exception of SYN segments, will have been right-shifted - by rcv.scale bits: - - SEG.WND = RCV.WND >> rcv.scale. - - - TCP determines if a data segment is "old" or "new" by testing if - its sequence number is within 2**31 bytes of the left edge of the - window. If not, the data is "old" and discarded. To insure that - new data is never mistakenly considered old and vice-versa, the - - - -Jacobson & Braden [Page 5] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - left edge of the sender's window has to be at least 2**31 away - from the right edge of the receiver's window. Similarly with the - sender's right edge and receiver's left edge. Since the right and - left edges of either the sender's or receiver's window differ by - the window size, and since the sender and receiver windows can be - out of phase by at most the window size, the above constraints - imply that 2 * the max window size must be less than 2**31, or - - max window < 2**30 - - Since the max window is 2**S (where S is the scaling shift count) - times at most 2**16 - 1 (the maximum unscaled window), the maximum - window is guaranteed to be < 2*30 if S <= 14. Thus, the shift - count must be limited to 14. (This allows windows of 2**30 = 1 - Gbyte.) If a Window Scale option is received with a shift.cnt - value exceeding 14, the TCP should log the error but use 14 - instead of the specified value. - - -3. TCP SELECTIVE ACKNOWLEDGMENT OPTIONS - - To minimize the impact on the TCP protocol, the selective - acknowledgment extension uses the form of two new TCP options. The - first is an enabling option, "SACK-permitted", that may be sent in a - SYN segment to indicate that the the SACK option may be used once the - connection is established. The other is the SACK option itself, - which may be sent over an established connection once permission has - been given by SACK-permitted. - - The SACK option is to be included in a segment sent from a TCP that - is receiving data to the TCP that is sending that data; we will refer - to these TCP's as the data receiver and the data sender, - respectively. We will consider a particular simplex data flow; any - data flowing in the reverse direction over the same connection can be - treated independently. - -3.1 SACK-Permitted Option - - This two-byte option may be sent in a SYN by a TCP that has been - extended to receive (and presumably process) the SACK option once - the connection has opened. - - - - - - - - - - -Jacobson & Braden [Page 6] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - TCP Sack-Permitted Option: - - Kind: 4 - - +---------+---------+ - | Kind=4 | Length=2| - +---------+---------+ - -3.2 SACK Option - - The SACK option is to be used to convey extended acknowledgment - information over an established connection. Specifically, it is - to be sent by a data receiver to inform the data transmitter of - non-contiguous blocks of data that have been received and queued. - The data receiver is awaiting the receipt of data in later - retransmissions to fill the gaps in sequence space between these - blocks. At that time, the data receiver will acknowledge the data - normally by advancing the left window edge in the Acknowledgment - Number field of the TCP header. - - It is important to understand that the SACK option will not change - the meaning of the Acknowledgment Number field, whose value will - still specify the left window edge, i.e., one byte beyond the last - sequence number of fully-received data. The SACK option is - advisory; if it is ignored, TCP acknowledgments will continue to - function as specified in the protocol. - - However, SACK will provide additional information that the data - transmitter can use to optimize retransmissions. The TCP data - receiver may include the SACK option in an acknowledgment segment - whenever it has data that is queued and unacknowledged. Of - course, the SACK option may be sent only when the TCP has received - the SACK-permitted option in the SYN segment for that connection. - - TCP SACK Option: - - Kind: 5 - - Length: Variable - - - +--------+--------+--------+--------+--------+--------+...---+ - | Kind=5 | Length | Relative Origin | Block Size | | - +--------+--------+--------+--------+--------+--------+...---+ - - - This option contains a list of the blocks of contiguous sequence - space occupied by data that has been received and queued within - - - -Jacobson & Braden [Page 7] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - the window. Each block is contiguous and isolated; that is, the - octets just below the block, - - Acknowledgment Number + Relative Origin -1, - - and just above the block, - - Acknowledgment Number + Relative Origin + Block Size, - - have not been received. - - Each contiguous block of data queued at the receiver is defined in - the SACK option by two 16-bit integers: - - - * Relative Origin - - This is the first sequence number of this block, relative to - the Acknowledgment Number field in the TCP header (i.e., - relative to the data receiver's left window edge). - - - * Block Size - - This is the size in octets of this block of contiguous data. - - - A SACK option that specifies n blocks will have a length of 4*n+2 - octets, so the 44 bytes available for TCP options can specify a - maximum of 10 blocks. Of course, if other TCP options are - introduced, they will compete for the 44 bytes, and the limit of - 10 may be reduced in particular segments. - - There is no requirement on the order in which blocks can appear in - a single SACK option. - - Note: requiring that the blocks be ordered would allow a - slightly more efficient algorithm in the transmitter; however, - this does not seem to be an important optimization. - -3.3 SACK with Window Scaling - - If window scaling is in effect, then 16 bits may not be sufficient - for the SACK option fields that define the origin and length of a - block. There are two possible ways to handle this: - - (1) Expand the SACK origin and length fields to 24 or 32 bits. - - - - -Jacobson & Braden [Page 8] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - (2) Scale the SACK fields by the same factor as the window. - - - The first alternative would significantly reduce the number of - blocks possible in a SACK option; therefore, we have chosen the - second alternative, scaling the SACK information as well as the - window. - - Scaling the SACK information introduces some loss of precision, - since a SACK option must report queued data blocks whose origins - and lengths are multiples of the window scale factor rcv.scale. - These reported blocks must be equal to or smaller than the actual - blocks of queued data. - - Specifically, suppose that the receiver has a contiguous block of - queued data that occupies sequence numbers L, L+1, ... L+N-1, and - that the window scale factor is S = rcv.scale. Then the - corresponding block that will be reported in a SACK option will - be: - - Relative Origin = int((L+S-1)/S) - - Block Size = int((L+N)/S) - (Relative Origin) - - where the function int(x) returns the greatest integer contained - in x. - - The resulting loss of precision is not a serious problem for the - sender. If the data-sending TCP keeps track of the boundaries of - all segments in its retransmission queue, it will generally be - able to infer from the imprecise SACK data which full segments - don't need to be retransmitted. This will fail only if S is - larger than the maximum segment size, in which case some segments - may be retransmitted unnecessarily. If the sending TCP does not - keep track of transmitted segment boundaries, the imprecision of - the scaled SACK quantities will only result in retransmitting a - small amount of unneeded sequence space. On the average, the data - sender will unnecessarily retransmit J*S bytes of the sequence - space for each SACK received; here J is the number of blocks - reported in the SACK, and S = snd.scale. - -3.4 SACK Option Examples - - Assume the left window edge is 5000 and that the data transmitter - sends a burst of 8 segments, each containing 500 data bytes. - Unless specified otherwise, we assume that the scale factor S = 1. - - - - - -Jacobson & Braden [Page 9] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - Case 1: The first 4 segments are received but the last 4 are - dropped. - - The data receiver will return a normal TCP ACK segment - acknowledging sequence number 7000, with no SACK option. - - - Case 2: The first segment is dropped but the remaining 7 are - received. - - The data receiver will return a TCP ACK segment that - acknowledges sequence number 5000 and contains a SACK option - specifying one block of queued data: - - Relative Origin = 500; Block Size = 3500 - - - Case 3: The 2nd, 4th, 6th, and 8th (last) segments are - dropped. - - The data receiver will return a TCP ACK segment that - acknowledges sequence number 5500 and contains a SACK option - specifying the 3 blocks: - - Relative Origin = 500; Block Size = 500 - Relative Origin = 1500; Block Size = 500 - Relative Origin = 2500; Block Size = 500 - - - Case 4: Same as Case 3, except Scale Factor S = 16. - - The SACK option would specify the 3 scaled blocks: - - Relative Origin = 32; Block Size = 30 - Relative Origin = 94; Block Size = 31 - Relative Origin = 157; Block Size = 30 - - These three reported blocks have sequence numbers 512 through - 991, 1504 through 1999, and 2512 through 2992, respectively. - - -3.5 Generating the SACK Option - - Let us assume that the data receiver maintains a queue of valid - segments that it has neither passed to the user nor acknowledged - because of earlier missing data, and that this queue is ordered by - starting sequence number. Computation of the SACK option can be - done with one pass down this queue. Segments that occupy - - - -Jacobson & Braden [Page 10] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - contiguous sequence space are aggregated into a single SACK block, - and each gap in the sequence space (except a gap that is - terminated by the right window edge) triggers the start of a new - SACK block. If this algorithm defines more than 10 blocks, only - the first 10 can be included in the option. - -3.6 Interpreting the SACK Option - - The data transmitter is assumed to have a retransmission queue - that contains the segments that have been transmitted but not yet - acknowledged, in sequence-number order. If the data transmitter - performs re-packetization before retransmission, the block - boundaries in a SACK option that it receives may not fall on - boundaries of segments in the retransmission queue; however, this - does not pose a serious difficulty for the transmitter. - - Let us suppose that for each segment in the retransmission queue - there is a (new) flag bit "ACK'd", to be used to indicate that - this particular segment has been entirely acknowledged. When a - segment is first transmitted, it will be entered into the - retransmission queue with its ACK'd bit off. If the ACK'd bit is - subsequently turned on (as the result of processing a received - SACK option), the data transmitter will skip this segment during - any later retransmission. However, the segment will not be - dequeued and its buffer freed until the left window edge is - advanced over it. - - When an acknowledgment segment arrives containing a SACK option, - the data transmitter will turn on the ACK'd bits for segments that - have been selectively acknowleged. More specifically, for each - block in the SACK option, the data transmitter will turn on the - ACK'd flags for all segments in the retransmission queue that are - wholly contained within that block. This requires straightforward - sequence number comparisons. - - -4. TCP ECHO OPTIONS - - A simple method for measuring the RTT of a segment would be: the - sender places a timestamp in the segment and the receiver returns - that timestamp in the corresponding ACK segment. When the ACK segment - arrives at the sender, the difference between the current time and - the timestamp is the RTT. To implement this timing method, the - receiver must simply reflect or echo selected data (the timestamp) - from the sender's segments. This idea is the basis of the "TCP Echo" - and "TCP Echo Reply" options. - - - - - -Jacobson & Braden [Page 11] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - -4.1 TCP Echo and TCP Echo Reply Options - - TCP Echo Option: - - Kind: 6 - - Length: 6 - - +--------+--------+--------+--------+--------+--------+ - | Kind=6 | Length | 4 bytes of info to be echoed | - +--------+--------+--------+--------+--------+--------+ - - This option carries four bytes of information that the receiving TCP - may send back in a subsequent TCP Echo Reply option (see below). A - TCP may send the TCP Echo option in any segment, but only if a TCP - Echo option was received in a SYN segment for the connection. - - When the TCP echo option is used for RTT measurement, it will be - included in data segments, and the four information bytes will define - the time at which the data segment was transmitted in any format - convenient to the sender. - - TCP Echo Reply Option: - - Kind: 7 - - Length: 6 - - +--------+--------+--------+--------+--------+--------+ - | Kind=7 | Length | 4 bytes of echoed info | - +--------+--------+--------+--------+--------+--------+ - - - A TCP that receives a TCP Echo option containing four information - bytes will return these same bytes in a TCP Echo Reply option. - - This TCP Echo Reply option must be returned in the next segment - (e.g., an ACK segment) that is sent. If more than one Echo option is - received before a reply segment is sent, the TCP must choose only one - of the options to echo, ignoring the others; specifically, it must - choose the newest segment with the oldest sequence number (see next - section.) - - To use the TCP Echo and Echo Reply options, a TCP must send a TCP - Echo option in its own SYN segment and receive a TCP Echo option in a - SYN segment from the other TCP. A TCP that does not implement the - TCP Echo or Echo Reply options must simply ignore any TCP Echo - options it receives. However, a TCP should not receive one of these - - - -Jacobson & Braden [Page 12] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - options in a non-SYN segment unless it included a TCP Echo option in - its own SYN segment. - -4.2 Using the Echo Options - - If we wish to use the Echo/Echo Reply options for RTT measurement, we - have to define what the receiver does when there is not a one-to-one - correspondence between data and ACK segments. Assuming that we want - to minimize the state kept in the receiver (i.e., the number of - unprocessed Echo options), we can plan on a receiver remembering the - information value from at most one Echo between ACKs. There are - three situations to consider: - - (A) Delayed ACKs. - - Many TCP's acknowledge only every Kth segment out of a group of - segments arriving within a short time interval; this policy is - known generally as "delayed ACK's". The data-sender TCP must - measure the effective RTT, including the additional time due to - delayed ACK's, or else it will retransmit unnecessarily. Thus, - when delayed ACK's are in use, the receiver should reply with - the Echo option information from the earliest unacknowledged - segment. - - (B) A hole in the sequence space (segment(s) have been lost). - - The sender will continue sending until the window is filled, and - we may be generating ACKs as these out-of-order segments arrive - (e.g., for the SACK information or to aid "fast retransmit"). - An Echo Reply option will tell the sender the RTT of some - recently sent segment (since the ACK can only contain the - sequence number of the hole, the sender may not be able to - determine which segment, but that doesn't matter). If the loss - was due to congestion, these RTTs may be particularly valuable - to the sender since they reflect the network characteristics - immediately after the congestion. - - (C) A filled hole in the sequence space. - - The segment that fills the hole represents the most recent - measurement of the network characteristics. On the other hand, - an RTT computed from an earlier segment would probably include - the sender's retransmit time-out, badly biasing the sender's - average RTT estimate. - - - Case (A) suggests the receiver should remember and return the Echo - option information from the oldest unacknowledged segment. Cases (B) - - - -Jacobson & Braden [Page 13] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - and (C) suggest that the option should come from the most recent - unacknowledged segment. An algorithm that covers all three cases is - for the receiver to return the Echo option information from the - newest segment with the oldest sequence number, as specified earlier. - - A model implementation of these options is as follows. - - - (1) Receiver Implementation - - A 32-bit slot for Echo option data, rcv.echodata, is added to - the receiver connection state, together with a flag, - rcv.echopresent, that indicates whether there is anything in the - slot. When the receiver generates a segment, it checks - rcv.echopresent and, if it is set, adds an echo-reply option - containing rcv.echodata to the outgoing segment then clears - rcv.echopresent. - - If an incoming segment is in the window and contains an echo - option, the receiver checks rcv.echopresent. If it isn't set, - the value of the echo option is copied to rcv.echodata and - rcv.echopresent is set. If rcv.echopresent is already set, the - receiver checks whether the segment is at the left edge of the - window. If so, the segment's echo option value is copied to - rcv.echodata (this is situation (C) above). Otherwise, the - segment's echo option is ignored. - - - (2) Sender Implementation - - The sender's connection state has a single flag bit, - snd.echoallowed, added. If snd.echoallowed is set or if the - segment contains a SYN, the sender is free to add a TCP Echo - option (presumably containing the current time in some units - convenient to the sender) to every outgoing segment. - - Snd.echoallowed should be set if a SYN is received with a TCP - Echo option (presumably, a host that implements the option will - attempt to use it to time the SYN segment). - - -5. CONCLUSIONS AND ACKNOWLEDGMENTS - -We have proposed five new TCP options for scaled windows, selective -acknowledgments, and round-trip timing, in order to provide efficient -operation over large-bandwidth*delay-product paths. These extensions -are designed to provide compatible interworking with TCP's that do not -implement the extensions. - - - -Jacobson & Braden [Page 14] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - -The Window Scale option was originally suggested by Mike St. Johns of -USAF/DCA. The present form of the option was suggested by Mike Karels -of UC Berkeley in response to a more cumbersome scheme proposed by Van -Jacobson. Gerd Beling of FGAN (West Germany) contributed the initial -definition of the SACK option. - -All three options have evolved through discussion with the End-to-End -Task Force, and the authors are grateful to the other members of the -Task Force for their advice and encouragement. - -6. REFERENCES - - [Cheriton88] Cheriton, D., "VMTP: Versatile Message Transaction - Protocol", RFC 1045, Stanford University, February 1988. - - [Jain86] Jain, R., "Divergence of Timeout Algorithms for Packet - Retransmissions", Proc. Fifth Phoenix Conf. on Comp. and Comm., - Scottsdale, Arizona, March 1986. - - [Karn87] Karn, P. and C. Partridge, "Estimating Round-Trip Times - in Reliable Transport Protocols", Proc. SIGCOMM '87, Stowe, VT, - August 1987. - - [Clark87] Clark, D., Lambert, M., and L. Zhang, "NETBLT: A Bulk - Data Transfer Protocol", RFC 998, MIT, March 1987. - - [Nagle84] Nagle, J., "Congestion Control in IP/TCP - Internetworks", RFC 896, FACC, January 1984. - - [NBS85] Colella, R., Aronoff, R., and K. Mills, "Performance - Improvements for ISO Transport", Ninth Data Comm Symposium, - published in ACM SIGCOMM Comp Comm Review, vol. 15, no. 5, - September 1985. - - [Partridge87] Partridge, C., "Private Communication", February - 1987. - - [Postel81] Postel, J., "Transmission Control Protocol - DARPA - Internet Program Protocol Specification", RFC 793, DARPA, - September 1981. - - [Velten84] Velten, D., Hinden, R., and J. Sax, "Reliable Data - Protocol", RFC 908, BBN, July 1984. - - [Jacobson88] Jacobson, V., "Congestion Avoidance and Control", to - be presented at SIGCOMM '88, Stanford, CA., August 1988. - - [Zhang86] Zhang, L., "Why TCP Timers Don't Work Well", Proc. - - - -Jacobson & Braden [Page 15] - -RFC 1072 TCP Extensions for Long-Delay Paths October 1988 - - - SIGCOMM '86, Stowe, Vt., August 1986. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Jacobson & Braden [Page 16] - diff --git a/ext/picotcp/RFC/rfc1106.txt b/ext/picotcp/RFC/rfc1106.txt deleted file mode 100644 index 95fb0f5..0000000 --- a/ext/picotcp/RFC/rfc1106.txt +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - -Network Working Group R. Fox -Request for Comments: 1106 Tandem - June 1989 - - - TCP Big Window and Nak Options - -Status of this Memo - - This memo discusses two extensions to the TCP protocol to provide a - more efficient operation over a network with a high bandwidth*delay - product. The extensions described in this document have been - implemented and shown to work using resources at NASA. This memo - describes an Experimental Protocol, these extensions are not proposed - as an Internet standard, but as a starting point for further - research. Distribution of this memo is unlimited. - -Abstract - - Two extensions to the TCP protocol are described in this RFC in order - to provide a more efficient operation over a network with a high - bandwidth*delay product. The main issue that still needs to be - solved is congestion versus noise. This issue is touched on in this - memo, but further research is still needed on the applicability of - the extensions in the Internet as a whole infrastructure and not just - high bandwidth*delay product networks. Even with this outstanding - issue, this document does describe the use of these options in the - isolated satellite network environment to help facilitate more - efficient use of this special medium to help off load bulk data - transfers from links needed for interactive use. - -1. Introduction - - Recent work on TCP has shown great performance gains over a variety - of network paths [1]. However, these changes still do not work well - over network paths that have a large round trip delay (satellite with - a 600 ms round trip delay) or a very large bandwidth - (transcontinental DS3 line). These two networks exhibit a higher - bandwidth*delay product, over 10**6 bits, than the 10**5 bits that - TCP is currently limited to. This high bandwidth*delay product - refers to the amount of data that may be unacknowledged so that all - of the networks bandwidth is being utilized by TCP. This may also be - referred to as "filling the pipe" [2] so that the sender of data can - always put data onto the network and the receiver will always have - something to read, and neither end of the connection will be forced - to wait for the other end. - - After the last batch of algorithm improvements to TCP, performance - - - -Fox [Page 1] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - over high bandwidth*delay networks is still very poor. It appears - that no algorithm changes alone will make any significant - improvements over high bandwidth*delay networks, but will require an - extension to the protocol itself. This RFC discusses two possible - options to TCP for this purpose. - - The two options implemented and discussed in this RFC are: - - 1. NAKs - - This extension allows the receiver of data to inform the sender - that a packet of data was not received and needs to be resent. - This option proves to be useful over any network path (both high - and low bandwidth*delay type networks) that experiences periodic - errors such as lost packets, noisy links, or dropped packets due - to congestion. The information conveyed by this option is - advisory and if ignored, does not have any effect on TCP what so - ever. - - 2. Big Windows - - This option will give a method of expanding the current 16 bit (64 - Kbytes) TCP window to 32 bits of which 30 bits (over 1 gigabytes) - are allowed for the receive window. (The maximum window size - allowed in TCP due to the requirement of TCP to detect old data - versus new data. For a good explanation please see [2].) No - changes are required to the standard TCP header [6]. The 16 bit - field in the TCP header that is used to convey the receive window - will remain unchanged. The 32 bit receive window is achieved - through the use of an option that contains the upper half of the - window. It is this option that is necessary to fill large data - pipes such as a satellite link. - - This RFC is broken up into the following sections: section 2 will - discuss the operation of the NAK option in greater detail, section 3 - will discuss the big window option in greater detail. Section 4 will - discuss other effects of the big windows and nak feature when used - together. Included in this section will be a brief discussion on the - effects of congestion versus noise to TCP and possible options for - satellite networks. Section 5 will be a conclusion with some hints - as to what future development may be done at NASA, and then an - appendix containing some test results is included. - -2. NAK Option - - Any packet loss in a high bandwidth*delay network will have a - catastrophic effect on throughput because of the simple - acknowledgement of TCP. TCP always acks the stream of data that has - - - -Fox [Page 2] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - successfully been received and tells the sender the next byte of data - of the stream that is expected. If a packet is lost and succeeding - packets arrive the current protocol has no way of telling the sender - that it missed one packet but received following packets. TCP - currently resends all of the data over again, after a timeout or the - sender suspects a lost packet due to a duplicate ack algorithm [1], - until the receiver receives the lost packet and can then ack the lost - packet as well as succeeding packets received. On a normal low - bandwidth*delay network this effect is minimal if the timeout period - is set short enough. However, on a long delay network such as a T1 - satellite channel this is catastrophic because by the time the lost - packet can be sent and the ack returned the TCP window would have - been exhausted and both the sender and receiver would be temporarily - stalled waiting for the packet and ack to fully travel the data pipe. - This causes the pipe to become empty and requires the sender to - refill the pipe after the ack is received. This will cause a minimum - of 3*X bandwidth loss, where X is the one way delay of the medium and - may be much higher depending on the size of the timeout period and - bandwidth*delay product. Its 1X for the packet to be resent, 1X for - the ack to be received and 1X for the next packet being sent to reach - the destination. This calculation assumes that the window size is - much smaller than the pipe size (window = 1/2 data pipe or 1X), which - is the typical case with the current TCP window limitation over long - delay networks such as a T1 satellite link. - - An attempt to reduce this wasted bandwidth from 3*X was introduced in - [1] by having the sender resend a packet after it notices that a - number of consecutively received acks completely acknowledges already - acknowledged data. On a typical network this will reduce the lost - bandwidth to almost nil, since the packet will be resent before the - TCP window is exhausted and with the data pipe being much smaller - than the TCP window, the data pipe will not become empty and no - bandwidth will be lost. On a high delay network the reduction of - lost bandwidth is minimal such that lost bandwidth is still - significant. On a very noisy satellite, for instance, the lost - bandwidth is very high (see appendix for some performance figures) - and performance is very poor. - - There are two methods of informing the sender of lost data. - Selective acknowledgements and NAKS. Selective acknowledgements have - been the object of research in a number of experimental protocols - including VMTP [3], NETBLT [4], and SatFTP [5]. The idea behind - selective acks is that the receiver tells the sender which pieces it - received so that the sender can resend the data not acked but already - sent once. NAKs on the other hand, tell the sender that a particular - packet of data needs to be resent. - - There are a couple of disadvantages of selective acks. Namely, in - - - -Fox [Page 3] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - some of the protocols mentioned above, the receiver waits a certain - time before sending the selective ack so that acks may be bundled up. - This delay can cause some wasted bandwidth and requires more complex - state information than the simple nak. Even if the receiver doesn't - bundle up the selective acks but sends them as it notices that - packets have been lost, more complex state information is needed to - determine which packets have been acked and which packets need to be - resent. With naks, only the immediate data needed to move the left - edge of the window is naked, thus almost completely eliminating all - state information. - - The selective ack has one advantage over naks. If the link is very - noisy and packets are being lost close together, then the sender will - find out about all of the missing data at once and can send all of - the missing data out immediately in an attempt to move the left - window edge in the acknowledge number of the TCP header, thus keeping - the data pipe flowing. Whereas with naks, the sender will be - notified of lost packets one at a time and this will cause the sender - to process extra packets compared to selective acks. However, - empirical studies has shown that most lost packets occur far enough - apart that the advantage of selective acks over naks is rarely seen. - Also, if naks are sent out as soon as a packet has been determined - lost, then the advantage of selective acks becomes no more than - possibly a more aesthetic algorithm for handling lost data, but - offers no gains over naks as described in this paper. It is this - reason that the simplicity of naks was chosen over selective acks for - the current implementation. - -2.1 Implementation details - - When the receiver of data notices a gap between the expected sequence - number and the actual sequence number of the packet received, the - receiver can assume that the data between the two sequence numbers is - either going to arrive late or is lost forever. Since the receiver - can not distinguish between the two events a nak should be sent in - the TCP option field. Naking a packet still destined to arrive has - the effect of causing the sender to resend the packet, wasting one - packets worth of bandwidth. Since this event is fairly rare, the - lost bandwidth is insignificant as compared to that of not sending a - nak when the packet is not going to arrive. The option will take the - form as follows: - - +========+=========+=========================+================+ - +option= + length= + sequence number of + number of + - + A + 7 + first byte being naked + segments naked + - +========+=========+=========================+================+ - - This option contains the first sequence number not received and a - - - -Fox [Page 4] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - count of how many segments of bytes needed to be resent, where - segments is the size of the current TCP MSS being used for the - connection. Since a nak is an advisory piece of information, the - sending of a nak is unreliable and no means for retransmitting a nak - is provided at this time. - - When the sender of data receives the option it may either choose to - do nothing or it will resend the missing data immediately and then - continue sending data where it left off before receiving the nak. - The receiver will keep track of the last nak sent so that it will not - repeat the same nak. If it were to repeat the same nak the protocol - could get into the mode where on every reception of data the receiver - would nak the first missing data frame. Since the data pipe may be - very large by the time the first nak is read and responded to by the - sender, many naks would have been sent by the receiver. Since the - sender does not know that the naks are repetitious it will resend the - data each time, thus wasting the network bandwidth with useless - retransmissions of the same piece of data. Having an unreliable nak - may result in a nak being damaged and not being received by the - sender, and in this case, we will let the tcp recover by its normal - means. Empirical data has shown that the likelihood of the nak being - lost is quite small and thus, this advisory nak option works quite - well. - -3. Big Window Option - - Currently TCP has a 16 bit window limitation built into the protocol. - This limits the amount of outstanding unacknowledged data to 64 - Kbytes. We have already seen that some networks have a pipe larger - than 64 Kbytes. A T1 satellite channel and a cross country DS3 - network with a 30ms delay have data pipes much larger than 64 Kbytes. - Thus, even on a perfectly conditioned link with no bandwidth wasted - due to errors, the data pipe will not be filled and bandwidth will be - wasted. What is needed is the ability to send more unacknowledged - data. This is achieved by having bigger windows, bigger than the - current limitation of 16 bits. This option to expands the window - size to 30 bits or over 1 gigabytes by literally expanding the window - size mechanism currently used by TCP. The added option contains the - upper 15 bits of the window while the lower 16 bits will continue to - go where they normally go [6] in the TCP header. - - A TCP session will use the big window options only if both sides - agree to use them, otherwise the option is not used and the normal 16 - bit windows will be used. Once the 2 sides agree to use the big - windows then every packet thereafter will be expected to contain the - window option with the current upper 15 bits of the window. The - negotiation to decide whether or not to use the bigger windows takes - place during the SYN and SYN ACK segments of the TCP connection - - - -Fox [Page 5] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - startup process. The originator of the connection will include in - the SYN segment the following option: - - 1 byte 1 byte 4 bytes - +=========+==========+===============+ - +option=B + length=6 + 30 bit window + - +=========+==========+===============+ - - - If the other end of the connection wants to use big windows it will - include the same option back in the SYN ACK segment that it must - send. At this point, both sides have agreed to use big windows and - the specified windows will be used. It should be noted that the SYN - and SYN ACK segments will use the small windows, and once the big - window option has been negotiated then the bigger windows will be - used. - - Once both sides have agreed to use 32 bit windows the protocol will - function just as it did before with no difference in operation, even - in the event of lost packets. This claim holds true since the - rcv_wnd and snd_wnd variables of tcp contain the 16 bit windows until - the big window option is negotiated and then they are replaced with - the appropriate 32 bit values. Thus, the use of big windows becomes - part of the state information kept by TCP. - - Other methods of expanding the windows have been presented, including - a window multiple [2] or streaming [5], but this solution is more - elegant in the sense that it is a true extension of the window that - one day may easily become part of the protocol and not just be an - option to the protocol. - -3.1 How does it work - - Once a connection has decided to use big windows every succeeding - packet must contain the following option: - - +=========+==========+==========================+ - +option=C + length=4 + upper 15 bits of rcv_wnd + - +=========+==========+==========================+ - - With all segments sent, the sender supplies the size of its receive - window. If the connection is only using 16 bits then this option is - not supplied, otherwise the lower 16 bits of the receive window go - into the tcp header where it currently resides [6] and the upper 15 - bits of the window is put into the data portion of the option C. - When the receiver processes the packet it must first reform the - window and then process the packet as it would in the absence of the - option. - - - -Fox [Page 6] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - -3.2 Impact of changes - - In implementing the first version of the big window option there was - very little change required to the source. State information must be - added to the protocol to determine if the big window option is to be - used and all 16 bit variables that dealt with window information must - now become 32 bit quantities. A future document will describe in - more detail the changes required to the 4.3 bsd tcp source code. - Test results of the window change only are presented in the appendix. - When expanding 16 bit quantities to 32 bit quantities in the TCP - control block in the source (4.3 bsd source) may cause the structure - to become larger than the mbuf used to hold the structure. Care must - be taken to insure this doesn't occur with your system or - undetermined events may take place. - -4. Effects of Big Windows and Naks when used together - - With big windows alone, transfer times over a satellite were quite - impressive with the absence of any introduced errors. However, when - an error simulator was used to create random errors during transfers, - performance went down extremely fast. When the nak option was added - to the big window option performance in the face of errors went up - some but not to the level that was expected. This section will - discuss some issues that were overcome to produce the results given - in the appendix. - -4.1 Window Size and Nak benefits - - With out errors, the window size required to keep the data pipe full - is equal to the round trip delay * throughput desired, or the data - pipe bandwidth (called Z from now on). This and other calculations - assume that processing time of the hosts is negligible. In the event - of an error (without NAKs), the window size needs to become larger - than Z in order to keep the data pipe full while the sender is - waiting for the ack of the resent packet. If the window size is - equaled to Z and we assume that the retransmission timer is equaled - to Z, then when a packet is lost, the retransmission timer will go - off as the last piece of data in the window is sent. In this case, - the lost piece of data can be resent with no delay. The data pipe - will empty out because it will take 1/2Z worth of data to get the ack - back to the sender, an additional 1/2Z worth of data to get the data - pipe refilled with new data. This causes the required window to be - 2Z, 1Z to keep the data pipe full during normal operations and 1Z to - keep the data pipe full while waiting for a lost packet to be resent - and acked. - - If the same scenario in the last paragraph is used with the addition - of NAKs, the required window size still needs to be 2Z to avoid - - - -Fox [Page 7] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - wasting any bandwidth in the event of a dropped packet. This appears - to mean that the nak option does not provide any benefits at all. - Testing showed that the retransmission timer was larger than the data - pipe and in the event of errors became much bigger than the data - pipe, because of the retransmission backoff. Thus, the nak option - bounds the required window to 2Z such that in the event of an error - there is no lost bandwidth, even with the retransmission timer - fluctuations. The results in the appendix shows that by using naks, - bandwidth waste associated with the retransmission timer facility is - eliminated. - -4.2 Congestions vs Noise - - An issue that must be looked at when implementing both the NAKs and - big window scheme together is in the area of congestion versus lost - packets due to the medium, or noise. In the recent algorithm - enhancements [1], slow start was introduced so that whenever a data - transfer is being started on a connection or right after a dropped - packet, the effective send window would be set to a very small size - (typically would equal the MSS being used). This is done so that a - new connection would not cause congestion by immediately overloading - the network, and so that an existing connection would back off the - network if a packet was dropped due to congestion and allow the - network to clear up. If a connection using big windows loses a - packet due to the medium (a packet corrupted by an error) the last - thing that should be done is to close the send window so that the - connection can only send 1 packet and must use the slow start - algorithm to slowly work itself back up to sending full windows worth - of data. This algorithm would quickly limit the usefulness of the - big window and nak options over lossy links. - - On the other hand, if a packet was dropped due to congestion and the - sender assumes the packet was dropped because of noise the sender - will continue sending large amounts of data. This action will cause - the congestion to continue, more packets will be dropped, and that - part of the network will collapse. In this instance, the sender - would want to back off from sending at the current window limit. - Using the current slow start mechanism over a satellite builds up the - window too slowly [1]. Possibly a better solution would be for the - window to be opened 2*Rlog2(W) instead of R*log2(W) [1] (open window - by 2 packets instead of 1 for each acked packet). This will reduce - the wasted bandwidth by opening the window much quicker while giving - the network a chance to clear up. More experimentation is necessary - to find the optimal rate of opening the window, especially when large - windows are being used. - - The current recommendation for TCP is to use the slow start mechanism - in the event of any lost packet. If an application knows that it - - - -Fox [Page 8] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - will be using a satellite with a high error rate, it doesn't make - sense to force it to use the slow start mechanism for every dropped - packet. Instead, the application should be able to choose what - action should happen in the event of a lost packet. In the BSD - environment, a setsockopt call should be provided so that the - application may inform TCP to handle lost packets in a special way - for this particular connection. If the known error rate of a link is - known to be small, then by using slow start with modified rate from - above, will cause the amount of bandwidth loss to be very small in - respect to the amount of bandwidth actually utilized. In this case, - the setsockopt call should not be used. What is really needed is a - way for a host to determine if a packet or packets are being dropped - due to congestion or noise. Then, the host can choose to do the - right thing. This will require a mechanism like source quench to be - used. For this to happen more experimentation is necessary to - determine a solid definition on the use of this mechanism. Now it is - believed by some that using source quench to avoid congestion only - adds to the problem, not help suppress it. - - The TCP used to gather the results in the appendix for the big window - with nak experiment, assumed that lost packets were the result of - noise and not congestion. This assumption was used to show how to - make the current TCP work in such an environment. The actual - satellite used in the experiment (when the satellite simulator was - not used) only experienced an error rate around 10e-10. With this - error rate it is suggested that in practice when big windows are used - over the link, TCP should use the slow start mechanism for all lost - packets with the 2*Rlog2(W) rate discussed above. Under most - situations when long delay networks are being used (transcontinental - DS3 networks using fiber with very low error rates, or satellite - links with low error rates) big windows and naks should be used with - the assumption that lost packets are the result of congestion until a - better algorithm is devised [7]. - - Another problem noticed, while testing the affects of slow start over - a satellite link, was at times, the retransmission timer was set so - restrictive, that milliseconds before a naked packet's ack is - received the retransmission timer would go off due to a timed packet - within the send window. The timer was set at the round trip delay of - the network allowing no time for packet processing. If this timer - went off due to congestion then backing off is the right thing to do, - otherwise to avoid the scenario discovered by experimentation, the - transmit timer should be set a little longer so that the - retransmission timer does not go off too early. Care must be taken - to make sure the right thing is done in the implementation in - question so that a packet isn't retransmitted too soon, and blamed on - congestion when in fact, the ack is on its way. - - - - -Fox [Page 9] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - -4.3 Duplicate Acks - - Another problem found with the 4.3bsd implementation is in the area - of duplicate acks. When the sender of data receives a certain number - of acks (3 in the current Berkeley release) that acknowledge - previously acked data before, it then assumes that a packet has been - lost and will resend the one packet assumed lost, and close its send - window as if the network is congested and the slow start algorithm - mention above will be used to open the send window. This facility is - no longer needed since the sender can use the reception of a nak as - its indicator that a particular packet was dropped. If the nak - packet is lost then the retransmit timer will go off and the packet - will be retransmitted by normal means. If a senders algorithm - continues to count duplicate acks the sender will find itself - possibly receiving many duplicate acks after it has already resent - the packet due to a nak being received because of the large size of - the data pipe. By receiving all of these duplicate acks the sender - may find itself doing nothing but resending the same packet of data - unnecessarily while keeping the send window closed for absolutely no - reason. By removing this feature of the implementation a user can - expect to find a satellite connection working much better in the face - of errors and other connections should not see any performance loss, - but a slight improvement in performance if anything at all. - -5. Conclusion - - This paper has described two new options that if used will make TCP a - more efficient protocol in the face of errors and a more efficient - protocol over networks that have a high bandwidth*delay product - without decreasing performance over more common networks. If a - system that implements the options talks with one that does not, the - two systems should still be able to communicate with no problems. - This assumes that the system doesn't use the option numbers defined - in this paper in some other way or doesn't panic when faced with an - option that the machine does not implement. Currently at NASA, there - are many machines that do not implement either option and communicate - just fine with the systems that do implement them. - - The drive for implementing big windows has been the direct result of - trying to make TCP more efficient over large delay networks [2,3,4,5] - such as a T1 satellite. However, another practical use of large - windows is becoming more apparent as the local area networks being - developed are becoming faster and supporting much larger MTU's. - Hyperchannel, for instances, has been stated to be able to support 1 - Mega bit MTU's in their new line of products. With the current - implementation of TCP, efficient use of hyperchannel is not utilized - as it should because the physical mediums MTU is larger than the - maximum window of the protocol being used. By increasing the TCP - - - -Fox [Page 10] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - window size, better utilization of networks like hyperchannel will be - gained instantly because the sender can send 64 Kbyte packets (IP - limitation) but not have to operate in a stop and wait fashion. - Future work is being started to increase the IP maximum datagram size - so that even better utilization of fast local area networks will be - seen by having the TCP/IP protocols being able to send large packets - over mediums with very large MTUs. This will hopefully, eliminate - the network protocol as the bottleneck in data transfers while - workstations and workstation file system technology advances even - more so, than it already has. - - An area of concern when using the big window mechanism is the use of - machine resources. When running over a satellite and a packet is - dropped such that 2Z (where Z is the round trip delay) worth of data - is unacknowledged, both ends of the connection need to be able to - buffer the data using machine mbufs (or whatever mechanism the - machine uses), usually a valuable and scarce commodity. If the - window size is not chosen properly, some machines will crash when the - memory is all used up, or it will keep other parts of the system from - running. Thus, setting the window to some fairly large arbitrary - number is not a good idea, especially on a general purpose machine - where many users log on at any time. What is currently being - engineered at NASA is the ability for certain programs to use the - setsockopt feature or 4.3bsd asking to use big windows such that the - average user may not have access to the large windows, thus limiting - the use of big windows to applications that absolutely need them and - to protect a valuable system resource. - -6. References - - [1] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM 88, - Stanford, Ca., August 1988. - - [2] Jacobson, V., and R. Braden, "TCP Extensions for Long-Delay - Paths", LBL, USC/Information Sciences Institute, RFC 1072, - October 1988. - - [3] Cheriton, D., "VMTP: Versatile Message Transaction Protocol", RFC - 1045, Stanford University, February 1988. - - [4] Clark, D., M. Lambert, and L. Zhang, "NETBLT: A Bulk Data - Transfer Protocol", RFC 998, MIT, March 1987. - - [5] Fox, R., "Draft of Proposed Solution for High Delay Circuit File - Transfer", GE/NAS Internal Document, March 1988. - - [6] Postel, J., "Transmission Control Protocol - DARPA Internet - Program Protocol Specification", RFC 793, DARPA, September 1981. - - - -Fox [Page 11] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - [7] Leiner, B., "Critical Issues in High Bandwidth Networking", RFC - 1077, DARPA, November 1989. - -7. Appendix - - Both options have been implemented and tested. Contained in this - section is some performance gathered to support the use of these two - options. The satellite channel used was a 1.544 Mbit link with a - 580ms round trip delay. All values are given as units of bytes. - - - TCP with Big Windows, No Naks: - - - |---------------transfer rates----------------------| - Window Size | no error | 10e-7 error rate | 10e-6 error rate | - ----------------------------------------------------------------- - 64K | 94K | 53K | 14K | - ----------------------------------------------------------------- - 72K | 106K | 51K | 15K | - ----------------------------------------------------------------- - 80K | 115K | 42K | 14K | - ----------------------------------------------------------------- - 92K | 115K | 43K | 14K | - ----------------------------------------------------------------- - 100K | 135K | 66K | 15K | - ----------------------------------------------------------------- - 112K | 126K | 53K | 17K | - ----------------------------------------------------------------- - 124K | 154K | 45K | 14K | - ----------------------------------------------------------------- - 136K | 160K | 66K | 15K | - ----------------------------------------------------------------- - 156K | 167K | 45K | 14K | - ----------------------------------------------------------------- - Figure 1. - - - - - - - - - - - - - - - -Fox [Page 12] - -RFC 1106 TCP Big Window and Nak Options June 1989 - - - TCP with Big Windows, and Naks: - - - |---------------transfer rates----------------------| - Window Size | no error | 10e-7 error rate | 10e-6 error rate | - ----------------------------------------------------------------- - 64K | 95K | 83K | 43K | - ----------------------------------------------------------------- - 72K | 104K | 87K | 49K | - ----------------------------------------------------------------- - 80K | 117K | 96K | 62K | - ----------------------------------------------------------------- - 92K | 124K | 119K | 39K | - ----------------------------------------------------------------- - 100K | 140K | 124K | 35K | - ----------------------------------------------------------------- - 112K | 151K | 126K | 53K | - ----------------------------------------------------------------- - 124K | 160K | 140K | 36K | - ----------------------------------------------------------------- - 136K | 167K | 148K | 38K | - ----------------------------------------------------------------- - 156K | 167K | 160K | 38K | - ----------------------------------------------------------------- - Figure 2. - - With a 10e-6 error rate, many naks as well as data packets were - dropped, causing the wild swing in transfer times. Also, please note - that the machines used are SGI Iris 2500 Turbos with the 3.6 OS with - the new TCP enhancements. The performance associated with the Irises - are slower than a Sun 3/260, but due to some source code restrictions - the Iris was used. Initial results on the Sun showed slightly higher - performance and less variance. - -Author's Address - - Richard Fox - 950 Linden #208 - Sunnyvale, Cal, 94086 - - EMail: rfox@tandem.com - - - - - - - - - - -Fox [Page 13] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1110.txt b/ext/picotcp/RFC/rfc1110.txt deleted file mode 100644 index 29a33e3..0000000 --- a/ext/picotcp/RFC/rfc1110.txt +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - -Network Working Group A. McKenzie -Request for Comments: 1110 BBN STC - August 1989 - - - A Problem with the TCP Big Window Option - -Status of this Memo - - This memo comments on the TCP Big Window option described in RFC - 1106. Distribution of this memo is unlimited. - -Abstract - - The TCP Big Window option discussed in RFC 1106 will not work - properly in an Internet environment which has both a high bandwidth * - delay product and the possibility of disordering and duplicating - packets. In such networks, the window size must not be increased - without a similar increase in the sequence number space. Therefore, - a different approach to big windows should be taken in the Internet. - -Discussion - - TCP was designed to work in a packet store-and-forward environment - characterized by the possibility of packet loss, packet disordering, - and packet duplication. Packet loss can occur, for example, by a - congested network element discarding a packet. Packet disordering - can occur, for example, by packets of a TCP connection being - arbitrarily transmitted partially over a low bandwidth terrestrial - path and partially over a high bandwidth satellite path. Packet - duplication can occur, for example, when two directly-connected - network elements use a reliable link protocol and the link goes down - after the receiver correctly receives a packet but before the - transmitter receives an acknowledgement for the packet; the - transmitter and receiver now each take responsibility for attempting - to deliver the same packet to its ultimate destination. - - TCP has the task of recreating at the destination an exact copy of - the data stream generated at the source, in the same order and with - no gaps or duplicates. The mechanism used to accomplish this task is - to assign a "unique" sequence number to each byte of data at its - source, and to sort the bytes at the destination according to the - sequence number. The sorting operation corrects any disordering. An - acknowledgement, timeout, and retransmission scheme corrects for data - loss. The uniqueness of the sequence number corrects for data - duplication. - - As a practical matter, however, the sequence number is not unique; it - - - -McKenzie [Page 1] - -RFC 1110 Comments on TCP Big Window Option August 1989 - - - is contained in a 32-bit field and therefore "wraps around" after the - transmission of 2**32 bytes of data. Two additional mechanisms are - used to insure the effective uniqueness of sequence numbers; these - are the TCP transmission window and bounds on packet lifetime within - the Internet, including the IP Time-to-Live (TTL). The transmission - window specifies the maximum number of bytes which may be sent by the - source in one source-destination roundtrip time. Since the TCP - transmission window is specified by 16 bits, which is 1/65536 of the - sequence number space, a sequence number will not be reused (used to - number another byte) for 65,536 roundtrip times. So long as the - combination of gateway action on the IP TTL and holding times within - the individual networks which interconnect the gateways do not allow - a packet's lifetime to exceed 65,536 roundtrip times, each sequence - number is effectively unique. It was believed by the TCP designers - that the networks and gateways forming the internet would meet this - constraint, and such has been the case. - - The proposed TCP Big Window option, as described in RFC 1106, expands - the size of the window specification to 30 bits, while leaving the - sequence number space unchanged. Thus, a sequence number can be - reused after 4 roundtrip times. Further, the Nak option allows a - packet to be retransmitted (i.e., potentially duplicated) by the - source after only one roundtrip time. Thus, if a packet becomes - "lost" in the Internet for only about 5 roundtrip times it may be - delivered when its sequence number again lies within the window, - albeit a later cycle of the window. In this case, TCP will not - necessarily recreate at the destination an exact copy of the data - stream generated at the source; it may replace some data with earlier - data. - - Of course, the problem described above results from the storage of - the "lost" packet within the net, and its subsequent out-of-order - delivery. RFC 1106 seems to describe use of the proposed options in - an isolated satellite network. We may hypothesize that this network - is memoryless, and thus cannot deliver packets out of order; it - either delivers a packet in order or loses it. If this is the case, - then there is no problem with the proposed options. The Internet, - however, can deliver packets out of order, and this will likely - continue to be true even if gigabit links become part of the - Internet. Therefore, the approach described in RFC 1106 cannot be - adopted for general Internet use. - - - - - - - - - - -McKenzie [Page 2] - -RFC 1110 Comments on TCP Big Window Option August 1989 - - -Author's Address - - Alex McKenzie - Bolt Beranek and Newman Inc. - 10 Moulton Street - Cambridge, MA 02238 - - Phone: (617) 873-2962 - - EMail: MCKENZIE@BBN.COM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McKenzie [Page 3] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1146.txt b/ext/picotcp/RFC/rfc1146.txt deleted file mode 100644 index c65b9d2..0000000 --- a/ext/picotcp/RFC/rfc1146.txt +++ /dev/null @@ -1,283 +0,0 @@ - - - - - - -Network Working Group J. Zweig -Request for Comments: 1146 UIUC -Obsoletes: RFC 1145 C. Partridge - BBN - March 1990 - - - TCP Alternate Checksum Options - -Status of This Memo - - This memo suggests a pair of TCP options to allow use of alternate - data checksum algorithms in the TCP header. The use of these options - is experimental, and not recommended for production use. - - Note: This RFC corrects errors introduced in the editing process in - RFC 1145. - - Distribution of this memo is unlimited. - -Introduction - - Some members of the networking community have expressed interest in - using checksum-algorithms with different error detection and - correction properties than the standard TCP checksum. The option - described in this memo provides a mechanism to negotiate the use of - an alternate checksum at connection-establishment time, as well as a - mechanism to carry additional checksum information for algorithms - that utilize checksums that are longer than 16 bits. - -Definition of the Options - - The TCP Alternate Checksum Request Option may be sent in a SYN - segment by a TCP to indicate that the TCP is prepared to both - generate and receive checksums based on an alternate algorithm. - During communication, the alternate checksum replaces the regular TCP - checksum in the checksum field of the TCP header. Should the - alternate checksum require more than 2 octets to transmit, the - checksum may either be moved into a TCP Alternate Checksum Data - Option and the checksum field of the TCP header be sent as 0, or the - data may be split between the header field and the option. Alternate - checksums are computed over the same data as the regular TCP checksum - (see TCP Alternate Checksum Data Option discussion below). - -TCP Alternate Checksum Request Option - - The format of the TCP Alternate Checksum Request Option is: - - - - -Zweig & Partridge [Page 1] - -RFC 1146 TCP Alternate Checksum Options March 1990 - - - +----------+----------+----------+ - | Kind=14 | Length=3 | chksum | - +----------+----------+----------+ - - Here chksum is a number identifying the type of checksum to be used. - - The currently defined values of chksum are: - - 0 -- TCP checksum - 1 -- 8-bit Fletcher's algorithm (see Appendix I) - 2 -- 16-bit Fletcher's algorithm (see Appendix II) - - Note that the 8-bit Fletcher algorithm gives a 16-bit checksum and - the 16-bit algorithm gives a 32-bit checksum. - - Alternate checksum negotiation proceeds as follows: - - A SYN segment used to originate a connection may contain the - Alternate Checksum Request Option, which specifies an alternate - checksum-calculation algorithm to be used for the connection. The - acknowledging SYN-ACK segment may also carry the option. - - If both SYN segments carry the Alternate Checksum Request option, - and both specify the same algorithm, that algorithm must be used - for the remainder of the connection. Otherwise, the standard TCP - checksum algorithm must be used for the entire connection. Thus, - for example, if one TCP specifies type 1 checksums, and the other - specifies type 2 checksums, then they will use type 0 (the regular - TCP checksum). Note that in practice, one TCP will typically be - responding to the other's SYN, and thus either accepting or - rejecting the proposed alternate checksum algorithm. - - Any segment with the SYN bit set must always use the standard TCP - checksum algorithm. Thus the SYN segment will always be - understood by the receiving TCP. The alternate checksum must not - be used until the first non-SYN segment. In addition, because RST - segments may also be received or sent without complete state - information, any segment with the RST bit set must use the - standard TCP checksum. - - The option may not be sent in any segment that does not have the - SYN bit set. - - An implementation of TCP which does not support the option should - silently ignore it (as RFC 1122 requires). Ignoring the option - will force any TCP attempting to use an alternate checksum to use - the standard TCP checksum algorithm, thus ensuring - interoperability. - - - -Zweig & Partridge [Page 2] - -RFC 1146 TCP Alternate Checksum Options March 1990 - - -TCP Alternate Checksum Data Option - - The format of the TCP Alternate Checksum Data Option is: - - +---------+---------+---------+ +---------+ - | Kind=15 |Length=N | data | ... | data | - +---------+---------+---------+ +---------+ - - This field is used only when the alternate checksum that is - negotiated is longer than 16 bits. These checksums will not fit in - the checksum field of the TCP header and thus at least part of them - must be put in an option. Whether the checksum is split between the - checksum field in the TCP header and the option or the entire - checksum is placed in the option is determined on a checksum by - checksum basis. - - The length of this option will depend on the choice of alternate - checksum algorithm for this connection. - - While computing the alternate checksum, the TCP checksum field and - the data portion TCP Alternate Checksum Data Option are replaced with - zeros. - - An otherwise acceptable segment carrying this option on a connection - using a 16-bit checksum algorithm, or carrying this option with an - inappropriate number of data octets for the chosen alternate checksum - algorithm is in error and must be discarded; a RST-segment must be - generated, and the connection aborted. - - Note the requirement above that RST and SYN segments must always use - the standard TCP checksum. - -APPENDIX I: The 8-bit Fletcher Checksum Algorithm - - The 8-bit Fletcher Checksum Algorithm is calculated over a sequence - of data octets (call them D[1] through D[N]) by maintaining 2 - unsigned 1's-complement 8-bit accumulators A and B whose contents are - initially zero, and performing the following loop where i ranges from - 1 to N: - - A := A + D[i] - B := B + A - - It can be shown that at the end of the loop A will contain the 8-bit - 1's complement sum of all octets in the datagram, and that B will - contain (N)D[1] + (N-1)D[2] + ... + D[N]. - - The octets covered by this algorithm should be the same as those over - - - -Zweig & Partridge [Page 3] - -RFC 1146 TCP Alternate Checksum Options March 1990 - - - which the standard TCP checksum calculation is performed, with the - pseudoheader being D[1] through D[12] and the TCP header beginning at - D[13]. Note that, for purposes of the checksum computation, the - checksum field itself must be equal to zero. - - At the end of the loop, the A goes in the first byte of the TCP - checksum and B goes in the second byte. - - Note that, unlike the OSI version of the Fletcher checksum, this - checksum does not adjust the check bytes so that the receiver - checksum is 0. - - There are a number of much faster algorithms for calculating the two - octets of the 8-bit Fletcher checksum. For more information see - [Sklower89], [Nakassis88] and [Fletcher82]. Naturally, any - computation which computes the same number as would be calculated by - the loop above may be used to calculate the checksum. One advantage - of the Fletcher algorithms over the standard TCP checksum algorithm - is the ability to detect the transposition of octets/words of any - size within a datagram. - -APPENDIX II: The 16-bit Fletcher Checksum Algorithm - - The 16-bit Fletcher Checksum algorithm proceeds in precisely the same - manner as the 8-bit checksum algorithm,, except that A, B and the - D[i] are 16-bit quantities. It is necessary (as it is with the - standard TCP checksum algorithm) to pad a datagram containing an odd - number of octets with a zero octet. - - Result A should be placed in the TCP header checksum field and Result - B should appear in an TCP Alternate Checksum Data option. This - option must be present in every TCP header. The two bytes reserved - for B should be set to zero during the calculation of the checksum. - - The checksum field of the TCP header shall contain the contents of A - at the end of the loop. The TCP Alternate Checksum Data option must - be present and contain the contents of B at the end of the loop. - -BIBLIOGRAPHY: - - [BrBoPa89] Braden, R., Borman, D., and C. Partridge, "Computing - the Internet Checksum", ACM Computer Communication - Review, Vol. 19, No. 2, pp. 86-101, April 1989. - [Note that this includes Plummer, W. "IEN-45: TCP - Checksum Function Design" (1978) as an appendix.] - - [Fletcher82] Fletcher, J., "An Arithmetic Checksum for Serial - Transmissions", IEEE Transactions on Communication, - - - -Zweig & Partridge [Page 4] - -RFC 1146 TCP Alternate Checksum Options March 1990 - - - Vol. COM-30, No. 1, pp. 247-252, January 1982. - - [Nakassis88] Nakassis, T., "Fletcher's Error Detection Algorithm: - How to implement it efficiently and how to avoid the - most common pitfalls", ACM Computer Communication - Review, Vol. 18, No. 5, pp. 86-94, October 1988. - - [Sklower89] Sklower, K., "Improving the Efficiency of the OSI - Checksum Calculation", ACM Computer Communication - Review, Vol. 19, No. 5, pp. 32-43, October 1989. - -Security Considerations - - Security issues are not addressed in this memo. - -Authors' Addresses - - Johnny Zweig - Digital Computer Lab - University of Illinois (UIUC) - 1304 West Springfield Avenue - CAMPUS MC 258 - Urbana, IL 61801 - - Phone: (217) 333-7937 - - EMail: zweig@CS.UIUC.EDU - - - Craig Partridge - Bolt Beranek and Newman Inc. - 50 Moulton Street - Cambridge, MA 02138 - - Phone: (617) 873-2459 - - EMail: craig@BBN.COM - - - - - - - - - - - - - - -Zweig & Partridge [Page 5] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1156.txt b/ext/picotcp/RFC/rfc1156.txt deleted file mode 100644 index 6a72a2e..0000000 --- a/ext/picotcp/RFC/rfc1156.txt +++ /dev/null @@ -1,5099 +0,0 @@ - - - - - - -Network Working Group K. McCloghrie -Request For Comments: 1156 Hughes LAN Systems -Obsoletes: RFC 1066 M. Rose - Performance Systems International - May 1990 - - - Management Information Base for Network Management - of TCP/IP-based internets - - Table of Contents - - 1. Status of this Memo ................................... 1 - 2. IAB Policy Statement .................................. 2 - 3. Introduction .......................................... 2 - 4. Objects ............................................... 6 - 4.1 Object Groups ........................................ 6 - 4.2 Format of Definitions ................................ 7 - 5. Object Definitions .................................... 8 - 5.1 The System Group ..................................... 9 - 5.2 The Interfaces Group ................................. 11 - 5.2.1 The Interfaces Table ............................... 11 - 5.3 The Address Translation Group ........................ 23 - 5.4 The IP Group ......................................... 26 - 5.4.1 The IP Address Table ............................... 34 - 5.4.2 The IP Routing Table ............................... 36 - 5.5 The ICMP Group ....................................... 43 - 5.6 The TCP Group ........................................ 53 - 5.7 The UDP Group ........................................ 62 - 5.8 The EGP Group ........................................ 64 - 5.8.1 The EGP Neighbor Table ............................. 65 - 6. Definitions ........................................... 68 - 7. Acknowledgements ...................................... 89 - 8. References ............................................ 90 - 9. Security Considerations................................ 91 - 10. Authors' Addresses.................................... 91 - -1. Status of this Memo - - This RFC is a re-release of RFC 1066, with a changed "Status of this - Memo", "IAB Policy Statement", and "Introduction" sections plus a few - minor typographical corrections. The technical content of the - document is unchanged from RFC 1066. - - This memo provides the initial version of the Management Information - Base (MIB) for use with network management protocols in TCP/IP-based - internets in the short-term. In particular, together with its - companion memos which describe the structure of management - - - -McCloghrie & Rose [Page 1] - -RFC 1156 MIB May 1990 - - - information along with the initial network management protocol, these - documents provide a simple, workable architecture and system for - managing TCP/IP-based internets and in particular the Internet. - - This memo specifies a Standard Protocol for the Internet community. - TCP/IP implementations in the Internet which are network manageable - are expected to adopt and implement this specification. - - The Internet Activities Board recommends that all IP and TCP - implementations be network manageable. This implies implementation - of the Internet MIB (RFC-1156) and at least one of the two - recommended management protocols SNMP (RFC-1157) or CMOT (RFC-1095). - It should be noted that, at this time, SNMP is a full Internet - standard and CMOT is a draft standard. See also the Host and Gateway - Requirements RFCs for more specific information on the applicability - of this standard. - - Please refer to the latest edition of the "IAB Official Protocol - Standards" RFC for current information on the state and status of - standard Internet protocols. - - Distribution of this memo is unlimited. - -2. IAB Policy Statement - - This MIB specification is the first edition of an evolving document - defining variables needed for monitoring and control of various - components of the Internet. Not all groups of defined variables are - mandatory for all Internet components. - - For example, the EGP group is mandatory for gateways using EGP but - not for hosts which should not be running EGP. Similarly, the TCP - group is mandatory for hosts running TCP but not for gateways which - aren't running it. What IS mandatory, however, is that all variables - of a group be supported if any element of the group is supported. - - It is expected that additional MIB groups and variables will be - defined over time to accommodate the monitoring and control needs of - new or changing components of the Internet. The responsible working - group(s) will continue to refine this specification. - -3. Introduction - - As reported in RFC 1052, IAB Recommendations for the Development of - Internet Network Management Standards [1], the Internet Activities - Board has directed the Internet Engineering Task Force (IETF) to - create two new working groups in the area of network management. One - group was charged with the further specification and definition of - - - -McCloghrie & Rose [Page 2] - -RFC 1156 MIB May 1990 - - - elements to be included in the Management Information Base. The - other was charged with defining the modifications to the Simple - Network Management Protocol (SNMP) to accommodate the short-term - needs of the network vendor and operator communities. In the long- - term, the use of the OSI network management framework was to be - examined using the ISO CMIS/CMIP [2,3] framework as a basis. Two - documents were produced to define the management information: RFC - 1065, which defined the Structure of Management Information (SMI) - [4], and RFC 1066, which defined the Management Information Base - (MIB) [5]. Both of these documents were designed so as to be - compatible with both the SNMP and the OSI network management - framework. - - This strategy was quite successful in the short-term: Internet-based - network management technology was fielded, by both the research and - commercial communities, within a few months. As a result of this, - portions of the Internet community became network manageable in a - timely fashion. - - As reported in RFC 1109, Report of the Second Ad Hoc Network - Management Review Group [6], the requirements of the SNMP and the OSI - network management frameworks were more different than anticipated. - As such, the requirement for compatibility between the SMI/MIB and - both frameworks was suspended. - - The IAB has designated the SNMP, SMI, and the initial Internet MIB to - be full "Standard Protocols" with "Recommended" status. By this - action, the IAB recommends that all IP and TCP implementations be - network manageable and that the implementations that are network - manageable are expected to adopt and implement the SMI, MIB, and - SNMP. - - As such, the current network management framework for TCP/IP- based - internets consists of: Structure and Identification of Management - Information for TCP/IP-based Internets, which describes how managed - objects contained in the MIB are defined as set forth in RFC 1155 - [7]; Management Information Base for Network Management of TCP/IP- - based Internets, which describes the managed objects contained in the - MIB as set forth in this memo; and, the Simple Network Management - Protocol, which defines the protocol used to manage these objects, as - set forth in RFC 1157 [8]. - - The IAB also urged the working groups to be "extremely sensitive to - the need to keep SNMP simple," and recommends that the MIB working - group take as its starting inputs the MIB definitions found in the - High-Level Entity Management Systems (HEMS) RFC 1024 [9], the initial - SNMP specification [10], and the CMIS/CMIP memos [11,12]. - - - - -McCloghrie & Rose [Page 3] - -RFC 1156 MIB May 1990 - - - Thus, the list of managed objects defined here, has been derived by - taking only those elements which are considered essential. Since - such elements are essential, there is no need to allow the - implementation of individual objects, to be optional. Rather, all - compliant implementations will contain all applicable (see below) - objects defined in this memo. - - This approach of taking only the essential objects is NOT - restrictive, since the SMI defined in the companion memo provides - three extensibility mechanisms: one, the addition of new standard - objects through the definitions of new versions of the MIB; two, the - addition of widely-available but non-standard objects through the - multilateral subtree; and three, the addition of private objects - through the enterprises subtree. Such additional objects can not only - be used for vendor-specific elements, but also for experimentation as - required to further the knowledge of which other objects are - essential. - - The primary criterion for being considered essential was for an - object to be contained in all of the above referenced MIB - definitions. A few other objects have been included, but only if the - MIB working group believed they are truly essential. The detailed - list of criteria against which potential inclusions in this (initial) - MIB were considered, was: - - 1) An object needed to be essential for either fault or - configuration management. - - 2) Only weak control objects were permitted (by weak, it - is meant that tampering with them can do only limited - damage). This criterion reflects the fact that the - current management protocols are not sufficiently secure - to do more powerful control operations. - - 3) Evidence of current use and utility was required. - - 4) An attempt was made to limit the number of objects to - about 100 to make it easier for vendors to fully - instrument their software. - - 5) To avoid redundant variables, it was required that no - object be included that can be derived from others in the - MIB. - - 6) Implementation specific objects (e.g., for BSD UNIX) - were excluded. - - 7) It was agreed to avoid heavily instrumenting critical - - - -McCloghrie & Rose [Page 4] - -RFC 1156 MIB May 1990 - - - sections of code. The general guideline was one counter - per critical section per layer. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 5] - -RFC 1156 MIB May 1990 - - -4. Objects - - Managed objects are accessed via a virtual information store, termed - the Management Information Base or MIB. Objects in the MIB are - defined using Abstract Syntax Notation One (ASN.1) [13]. - - The mechanisms used for describing these objects are specified in the - companion memo. In particular, each object has a name, a syntax, and - an encoding. The name is an object identifier, an administratively - assigned name, which specifies an object type. The object type - together with an object instance serves to uniquely identify a - specific instantiation of the object. For human convenience, we - often use a textual string, termed the OBJECT DESCRIPTOR, to also - refer to the object type. - - The syntax of an object type defines the abstract data structure - corresponding to that object type. The ASN.1 language is used for - this purpose. However, the companion memo purposely restricts the - ASN.1 constructs which may be used. These restrictions are - explicitly made for simplicity. - - The encoding of an object type is simply how that object type is - represented using the object type's syntax. Implicitly tied to the - notion of an object type's syntax and encoding is how the object type - is represented when being transmitted on the network. This memo - specifies the use of the basic encoding rules of ASN.1 [14]. - -4.1. Object Groups - - Since this list of managed objects contains only the essential - elements, there is no need to allow individual objects to be - optional. Rather, the objects are arranged into the following - groups: - - - System - - Interfaces - - Address Translation - - IP - - ICMP - - TCP - - UDP - - EGP - - There are two reasons for defining these groups: one, to provide a - means of assigning object identifiers; two, to provide a method for - implementations of managed agents to know which objects they must - implement. This method is as follows: if the semantics of a group is - applicable to an implementation, then it must implement all objects - - - -McCloghrie & Rose [Page 6] - -RFC 1156 MIB May 1990 - - - in that group. For example, an implementation must implement the EGP - group if and only if it implements the EGP protocol. - -4.2. Format of Definitions - - The next section contains the specification of all object types - contained in the MIB. Following the conventions of the companion - memo, the object types are defined using the following fields: - - OBJECT: - ------- - A textual name, termed the OBJECT DESCRIPTOR, for the - object type, along with its corresponding OBJECT - IDENTIFIER. - - Syntax: - The abstract syntax for the object type, presented using - ASN.1. This must resolve to an instance of the ASN.1 - type ObjectSyntax defined in the SMI. - - Definition: - A textual description of the semantics of the object - type. Implementations should ensure that their - interpretation of the object type fulfills this - definition since this MIB is intended for use in multi- - vendor environments. As such it is vital that object - types have consistent meaning across all machines. - - Access: - One of read-only, read-write, write-only, or - not-accessible. - - Status: - One of mandatory, optional, or obsolete. - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 7] - -RFC 1156 MIB May 1990 - - -5. Object Definitions - - RFC1156-MIB - - DEFINITIONS ::= BEGIN - - IMPORTS - mgmt, OBJECT-TYPE, NetworkAddress, IpAddress, - Counter, Gauge, TimeTicks - FROM RFC1155-SMI; - - mib OBJECT IDENTIFIER ::= { mgmt 1 } - - system OBJECT IDENTIFIER ::= { mib 1 } - interfaces OBJECT IDENTIFIER ::= { mib 2 } - at OBJECT IDENTIFIER ::= { mib 3 } - ip OBJECT IDENTIFIER ::= { mib 4 } - icmp OBJECT IDENTIFIER ::= { mib 5 } - tcp OBJECT IDENTIFIER ::= { mib 6 } - udp OBJECT IDENTIFIER ::= { mib 7 } - egp OBJECT IDENTIFIER ::= { mib 8 } - - END - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 8] - -RFC 1156 MIB May 1990 - - -5.1. The System Group - - Implementation of the System group is mandatory for all - systems. - - OBJECT: - ------- - sysDescr { system 1 } - - Syntax: - OCTET STRING - - Definition: - A textual description of the entity. This value should - include the full name and version identification of the - system's hardware type, software operating-system, and - networking software. It is mandatory that this only - contain printable ASCII characters. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - sysObjectID { system 2 } - - Syntax: - OBJECT IDENTIFIER - - Definition: - The vendor's authoritative identification of the network - management subsystem contained in the entity. This value - is allocated within the SMI enterprises subtree - (1.3.6.1.4.1) and provides an easy and unambiguous means - for determining "what kind of box" is being managed. For - example, if vendor "Flintstones, Inc." was assigned the - subtree 1.3.6.1.4.1.42, it could assign the identifier - 1.3.6.1.4.1.42.1.1 to its "Fred Router". - - Access: - read-only. - - Status: - mandatory. - - - -McCloghrie & Rose [Page 9] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - sysUpTime { system 3 } - - Syntax: - TimeTicks - - Definition: - The time (in hundredths of a second) since the network - management portion of the system was last re-initialized. - - Access: - read-only. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 10] - -RFC 1156 MIB May 1990 - - -5.2. The Interfaces Group - - Implementation of the Interfaces group is mandatory for all - systems. - - OBJECT: - ------- - ifNumber { interfaces 1 } - - Syntax: - INTEGER - - Definition: - The number of network interfaces (regardless of their - current state) on which this system can send/receive IP - datagrams. - - Access: - read-only. - - Status: - mandatory. - -5.2.1. The Interfaces Table - - OBJECT: - ------- - ifTable { interfaces 2 } - - Syntax: - SEQUENCE OF IfEntry - - Definition: - A list of interface entries. The number of entries is - given by the value of ifNumber. - - Access: - read-write. - - Status: - mandatory. - - OBJECT: - ------- - ifEntry { ifTable 1 } - - Syntax: - IfEntry ::= SEQUENCE { - - - -McCloghrie & Rose [Page 11] - -RFC 1156 MIB May 1990 - - - ifIndex - INTEGER, - ifDescr - OCTET STRING, - ifType - INTEGER, - ifMtu - INTEGER, - ifSpeed - Gauge, - ifPhysAddress - OCTET STRING, - ifAdminStatus - INTEGER, - ifOperStatus - INTEGER, - ifLastChange - TimeTicks, - ifInOctets - Counter, - ifInUcastPkts - Counter, - ifInNUcastPkts - Counter, - ifInDiscards - Counter, - ifInErrors - Counter, - ifInUnknownProtos - Counter, - ifOutOctets - Counter, - ifOutUcastPkts - Counter, - ifOutNUcastPkts - Counter, - ifOutDiscards - Counter, - ifOutErrors - Counter, - ifOutQLen - Gauge - } - - Definition: - An interface entry containing objects at the subnetwork - layer and below for a particular interface. - - - - -McCloghrie & Rose [Page 12] - -RFC 1156 MIB May 1990 - - - Access: - read-write. - - Status: - mandatory. - - - We now consider the individual components of each interface - entry: - - - OBJECT: - ------- - ifIndex { ifEntry 1 } - - Syntax: - INTEGER - - Definition: - A unique value for each interface. Its value ranges - between 1 and the value of ifNumber. The value for each - interface must remain constant at least from one re- - initialization of the entity's network management system - to the next re-initialization. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifDescr { ifEntry 2 } - - Syntax: - OCTET STRING - - Definition: - A text string containing information about the interface. - This string should include the name of the manufacturer, - the product name and the version of the hardware - interface. The string is intended for presentation to a - human; it must not contain anything but printable ASCII - characters. - - - - - -McCloghrie & Rose [Page 13] - -RFC 1156 MIB May 1990 - - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifType { ifEntry 3 } - - Syntax: - INTEGER { - other(1), -- none of the following - regular1822(2), - hdh1822(3), - ddn-x25(4), - rfc877-x25(5), - ethernet-csmacd(6), - iso88023-csmacd(7), - iso88024-tokenBus(8), - iso88025-tokenRing(9), - iso88026-man(10), - starLan(11), - proteon-10MBit(12), - proteon-80MBit(13), - hyperchannel(14), - fddi(15), - lapb(16), - sdlc(17), - t1-carrier(18), - cept(19), -- european equivalent of T-1 - basicIsdn(20), - primaryIsdn(21), - -- proprietary serial - propPointToPointSerial(22) - } - - Definition: - The type of interface, distinguished according to the - physical/link/network protocol(s) immediately "below" IP - in the protocol stack. - - Access: - read-only. - - Status: - mandatory. - - - -McCloghrie & Rose [Page 14] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ifMtu { ifEntry 4 } - - Syntax: - INTEGER - - Definition: - The size of the largest IP datagram which can be - sent/received on the interface, specified in octets. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifSpeed { ifEntry 5 } - - Syntax: - Gauge - - Definition: - An estimate of the interface's current bandwidth in bits - per second. For interfaces which do not vary in - bandwidth or for those where no accurate estimation can - be made, this object should contain the nominal - bandwidth. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifPhysAddress { ifEntry 6 } - - Syntax: - OCTET STRING - - Definition: - The interface's address at the protocol layer immediately - - - -McCloghrie & Rose [Page 15] - -RFC 1156 MIB May 1990 - - - "below" IP in the protocol stack. For interfaces which - do not have such an address (e.g., a serial line), this - object should contain an octet string of zero length. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifAdminStatus { ifEntry 7 } - - Syntax: - INTEGER { - up(1), -- ready to pass packets - down(2), - testing(3) -- in some test mode - } - - Definition: - The desired state of the interface. The testing(3) state - indicates that no operational packets can be passed. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ifOperStatus { ifEntry 8 } - - Syntax: - INTEGER { - up(1), -- ready to pass packets - down(2), - testing(3) -- in some test mode - } - - Definition: - The current operational state of the interface. The - testing(3) state indicates that no operational packets - can be passed. - - - -McCloghrie & Rose [Page 16] - -RFC 1156 MIB May 1990 - - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifLastChange { ifEntry 9 } - - Syntax: - TimeTicks - - Definition: - The value of sysUpTime at the time the interface entered - its current operational state. If the current state was - entered prior to the last re-initialization of the local - network management subsystem, then this object contains a - zero value. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifInOctets { ifEntry 10 } - - Syntax: - Counter - - Definition: - The total number of octets received on the interface, - including framing characters. - - Access: - read-only. - - Status: - mandatory. - - - - - - - -McCloghrie & Rose [Page 17] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ifInUcastPkts { ifEntry 11 } - - Syntax: - Counter - - Definition: - The number of (subnet) unicast packets delivered to a - higher-layer protocol. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifInNUcastPkts { ifEntry 12 } - - Syntax: - Counter - - Definition: - The number of non-unicast (i.e., subnet broadcast or - subnet multicast) packets delivered to a higher-layer - protocol. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifInDiscards { ifEntry 13 } - - Syntax: - Counter - - Definition: - 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 - - - -McCloghrie & Rose [Page 18] - -RFC 1156 MIB May 1990 - - - protocol. One possible reason for discarding such a - packet could be to free up buffer space. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifInErrors { ifEntry 14 } - - Syntax: - Counter - - Definition: - The number of inbound packets that contained errors - preventing them from being deliverable to a higher-layer - protocol. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifInUnknownProtos { ifEntry 15 } - - Syntax: - Counter - - Definition: - The number of packets received via the interface which - were discarded because of an unknown or unsupported - protocol. - - Access: - read-only. - - Status: - mandatory. - - - - - -McCloghrie & Rose [Page 19] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ifOutOctets { ifEntry 16 } - - Syntax: - Counter - - Definition: - The total number of octets transmitted out of the - interface, including framing characters. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifOutUcastPkts { ifEntry 17 } - - Syntax: - Counter - - Definition: - The total number of packets that higher-level protocols - requested be transmitted to a subnet-unicast address, - including those that were discarded or not sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifOutNUcastPkts { ifEntry 18 } - - Syntax: - Counter - - Definition: - The total number of packets that higher-level protocols - requested be transmitted to a non-unicast (i.e., a subnet - broadcast or subnet multicast) address, including those - - - -McCloghrie & Rose [Page 20] - -RFC 1156 MIB May 1990 - - - that were discarded or not sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifOutDiscards { ifEntry 19 } - - Syntax: - Counter - - Definition: - 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. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ifOutErrors { ifEntry 20 } - - Syntax: - Counter - - Definition: - The number of outbound packets that could not be - transmitted because of errors. - - Access: - read-only. - - Status: - mandatory. - - - - - -McCloghrie & Rose [Page 21] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ifOutQLen { ifEntry 21 } - - Syntax: - Gauge - - Definition: - The length of the output packet queue (in packets). - - Access: - read-only. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 22] - -RFC 1156 MIB May 1990 - - -5.3. The Address Translation Group - - Implementation of the Address Translation group is mandatory - for all systems. - - The Address Translation group contains one table which is the - union across all interfaces of the translation tables for - converting a NetworkAddress (e.g., an IP address) into a - subnetwork-specific address. For lack of a better term, this - document refers to such a subnetwork-specific address as a - "physical" address. - - Examples of such translation tables are: for broadcast media - where ARP is in use, the translation table is equivalent to - the ARP cache; or, on an X.25 network where non-algorithmic - translation to X.121 addresses is required, the translation - table contains the NetworkAddress to X.121 address - equivalences. - - OBJECT: - ------- - atTable { at 1 } - - Syntax: - SEQUENCE OF AtEntry - - Definition: - The Address Translation tables contain the NetworkAddress - to "physical" address equivalences. Some interfaces do - not use translation tables for determining address - equivalences (e.g., DDN-X.25 has an algorithmic method); - if all interfaces are of this type, then the Address - Translation table is empty, i.e., has zero entries. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - atEntry { atTable 1 } - - Syntax: - AtEntry ::= SEQUENCE { - atIfIndex - - - -McCloghrie & Rose [Page 23] - -RFC 1156 MIB May 1990 - - - INTEGER, - atPhysAddress - OCTET STRING, - atNetAddress - NetworkAddress - } - - Definition: - Each entry contains one NetworkAddress to "physical" - address equivalence. - - Access: - read-write. - - Status: - mandatory. - - We now consider the individual components of each Address - Translation table entry: - - - OBJECT: - ------- - atIfIndex { atEntry 1 } - - Syntax: - INTEGER - - Definition: - The interface on which this entry's equivalence is - effective. The interface identified by a particular - value of this index is the same interface as identified - by the same value of ifIndex. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - atPhysAddress { atEntry 2 } - - Syntax: - OCTET STRING - - - - -McCloghrie & Rose [Page 24] - -RFC 1156 MIB May 1990 - - - Definition: - The media-dependent "physical" address. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - atNetAddress { atEntry 3 } - - Syntax: - NetworkAddress - - Definition: - The NetworkAddress (e.g., the IP address) corresponding to - the media-dependent "physical" address. - - Access: - read-write. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 25] - -RFC 1156 MIB May 1990 - - -5.4. The IP Group - - Implementation of the IP group is mandatory for all systems. - - - OBJECT: - ------- - ipForwarding { ip 1 } - - Syntax: - INTEGER { - gateway(1), -- entity forwards datagrams - host(2) -- entity does NOT forward datagrams - } - - Definition: - The indication of whether this entity is acting as an IP - gateway in respect to the forwarding of datagrams - received by, but not addressed to, this entity. IP - gateways forward datagrams; Hosts do not (except those - Source-Routed via the host). - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipDefaultTTL { ip 2 } - - Syntax: - INTEGER - - Definition: - The default value inserted into the Time-To-Live field of - the IP header of datagrams originated at this entity, - whenever a TTL value is not supplied by the transport - layer protocol. - - Access: - read-write. - - Status: - mandatory. - - - - -McCloghrie & Rose [Page 26] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ipInReceives { ip 3 } - - Syntax: - Counter - - Definition: - The total number of input datagrams received from - interfaces, including those received in error. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipInHdrErrors { ip 4 } - - Syntax: - Counter - - Definition: - The number of input datagrams discarded due to errors in - their IP headers, including bad checksums, version number - mismatch, other format errors, time-to-live exceeded, - errors discovered in processing their IP options, etc. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipInAddrErrors { ip 5 } - - Syntax: - Counter - - Definition: - The number of input datagrams discarded because the IP - address in their IP header's destination field was not a - - - -McCloghrie & Rose [Page 27] - -RFC 1156 MIB May 1990 - - - valid address to be received at this entity. This count - includes invalid addresses (e.g., 0.0.0.0) and addresses - of unsupported Classes (e.g., Class E). For entities - which are not IP Gateways and therefore do not forward - datagrams, this counter includes datagrams discarded - because the destination address was not a local address. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipForwDatagrams { ip 6 } - - Syntax: - Counter - - Definition: - The number of input datagrams for which this entity was - not their final IP destination, as a result of which an - attempt was made to find a route to forward them to that - final destination. In entities which do not act as IP - Gateways, this counter will include only those packets - which were Source-Routed via this entity, and the - Source-Route option processing was successful. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipInUnknownProtos { ip 7 } - - Syntax: - Counter - - Definition: - The number of locally-addressed datagrams received - successfully but discarded because of an unknown or - unsupported protocol. - - - -McCloghrie & Rose [Page 28] - -RFC 1156 MIB May 1990 - - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipInDiscards { ip 8 } - - Syntax: - Counter - - Definition: - The number of input IP datagrams for which no problems - were encountered to prevent their continued processing, - but which were discarded (e.g. for lack of buffer space). - Note that this counter does not include any datagrams - discarded while awaiting re-assembly. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipInDelivers { ip 9 } - - Syntax: - Counter - - Definition: - The total number of input datagrams successfully - delivered to IP user-protocols (including ICMP). - - Access: - read-only. - - Status: - mandatory. - - OBJECT: - ------- - ipOutRequests { ip 10 } - - - -McCloghrie & Rose [Page 29] - -RFC 1156 MIB May 1990 - - - Syntax: - Counter - - Definition: - The total number of IP datagrams which local IP user- - protocols (including ICMP) supplied to IP in requests for - transmission. Note that this counter does not include - any datagrams counted in ipForwDatagrams. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipOutDiscards { ip 11 } - - Syntax: - Counter - - Definition: - The number of output IP datagrams for which no problem - was encountered to prevent their transmission to their - destination, but which were discarded (e.g., for lack of - buffer space). Note that this counter would include - datagrams counted in ipForwDatagrams if any such packets - met this (discretionary) discard criterion. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipOutNoRoutes { ip 12 } - - Syntax: - Counter - - - - - - - -McCloghrie & Rose [Page 30] - -RFC 1156 MIB May 1990 - - - Definition: - The number of IP datagrams discarded because no route - could be found to transmit them to their destination. - Note that this counter includes any packets counted in - ipForwDatagrams which meet this "no-route" criterion. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipReasmTimeout { ip 13 } - - Syntax: - INTEGER - - Definition: - The maximum number of seconds which received fragments - are held while they are awaiting reassembly at this - entity. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipReasmReqds { ip 14 } - - Syntax: - Counter - - Definition: - The number of IP fragments received which needed to be - reassembled at this entity. - - Access: - read-only. - - Status: - mandatory. - - - -McCloghrie & Rose [Page 31] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ipReasmOKs { ip 15 } - - Syntax: - Counter - - Definition: - The number of IP datagrams successfully re-assembled. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipReasmFails { ip 16 } - - Syntax: - Counter - - Definition: - The number of failures detected by the IP re-assembly - algorithm (for whatever reason: timed out, errors, etc). - - Note that this is not necessarily a count of discarded IP - fragments since some algorithms (notably RFC 815's) can - lose track of the number of fragments by combining them - as they are received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipFragOKs { ip 17 } - - Syntax: - Counter - - - - - -McCloghrie & Rose [Page 32] - -RFC 1156 MIB May 1990 - - - Definition: - The number of IP datagrams that have been successfully - fragmented at this entity. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipFragFails { ip 18 } - - Syntax: - Counter - - Definition: - The number of IP datagrams that have been discarded - because they needed to be fragmented at this entity but - could not be, e.g., because their "Don't Fragment" flag - was set. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipFragCreates { ip 19 } - - Syntax: - Counter - - Definition: - The number of IP datagram fragments that have been - generated as a result of fragmentation at this entity. - - Access: - read-only. - - Status: - mandatory. - - - - -McCloghrie & Rose [Page 33] - -RFC 1156 MIB May 1990 - - -5.4.1. The IP Address Table - - The Ip Address table contains this entity's IP addressing - information. - - - OBJECT: - ------- - ipAddrTable { ip 20 } - - Syntax: - SEQUENCE OF IpAddrEntry - - Definition: - The table of addressing information relevant to this - entity's IP addresses. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipAddrEntry { ipAddrTable 1 } - - Syntax: - IpAddrEntry ::= SEQUENCE { - ipAdEntAddr - IpAddress, - ipAdEntIfIndex - INTEGER, - ipAdEntNetMask - IpAddress, - ipAdEntBcastAddr - INTEGER - } - - Definition: - The addressing information for one of this entity's IP - addresses. - - Access: - read-only. - - - - - -McCloghrie & Rose [Page 34] - -RFC 1156 MIB May 1990 - - - Status: - mandatory. - - - OBJECT: - ------- - ipAdEntAddr { ipAddrEntry 1 } - - Syntax: - IpAddress - - Definition: - The IP address to which this entry's addressing - information pertains. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipAdEntIfIndex { ipAddrEntry 2 } - - Syntax: - INTEGER - - Definition: - The index value which uniquely identifies the interface - to which this entry is applicable. The interface - identified by a particular value of this index is the - same interface as identified by the same value of - ifIndex. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipAdEntNetMask { ipAddrEntry 3 } - - - - - -McCloghrie & Rose [Page 35] - -RFC 1156 MIB May 1990 - - - Syntax: - IpAddress - - Definition: - The subnet mask associated with the IP address of this - entry. The value of the mask is an IP address with all - the network bits set to 1 and all the hosts bits set to - 0. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipAdEntBcastAddr { ipAddrEntry 4 } - - Syntax: - INTEGER - - Definition: - The value of the least-significant bit in the IP - broadcast address used for sending datagrams on the - (logical) interface associated with the IP address of - this entry. For example, when the Internet standard - all-ones broadcast address is used, the value will be 1. - - Access: - read-only. - - Status: - mandatory. - -5.4.2. The IP Routing Table - - The IP Routing Table contains an entry for each route - presently known to this entity. Note that the action to be - taken in response to a request to read a non-existent entry, - is specific to the network management protocol being used. - - - OBJECT: - ------- - ipRoutingTable { ip 21 } - - - - -McCloghrie & Rose [Page 36] - -RFC 1156 MIB May 1990 - - - Syntax: - SEQUENCE OF IpRouteEntry - - Definition: - This entity's IP Routing table. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteEntry { ipRoutingTable 1 } - - Syntax: - IpRouteEntry ::= SEQUENCE { - ipRouteDest - IpAddress, - ipRouteIfIndex - INTEGER, - ipRouteMetric1 - INTEGER, - ipRouteMetric2 - INTEGER, - ipRouteMetric3 - INTEGER, - ipRouteMetric4 - INTEGER, - ipRouteNextHop - IpAddress, - ipRouteType - INTEGER, - ipRouteProto - INTEGER, - ipRouteAge - INTEGER - } - - Definition: - A route to a particular destination. - - Access: - read-write. - - - - - -McCloghrie & Rose [Page 37] - -RFC 1156 MIB May 1990 - - - Status: - mandatory. - - We now consider the individual components of each route in the - IP Routing Table: - - - OBJECT: - ------- - ipRouteDest { ipRouteEntry 1 } - - Syntax: - IpAddress - - Definition: - The destination IP address of this route. An entry with - a value of 0.0.0.0 is considered a default route. - Multiple such default routes can appear in the table, but - access to such multiple entries is dependent on the - table-access mechanisms defined by the network management - protocol in use. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteIfIndex { ipRouteEntry 2 } - - Syntax: - INTEGER - - Definition: - The index value which uniquely identifies the local - interface through which the next hop of this route should - be reached. The interface identified by a particular - value of this index is the same interface as identified - by the same value of ifIndex. - - Access: - read-write. - - Status: - mandatory. - - - -McCloghrie & Rose [Page 38] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ipRouteMetric1 { ipRouteEntry 3 } - - Syntax: - INTEGER - - Definition: - The primary routing metric for this route. The semantics - of this metric are determined by the routing-protocol - specified in the route's ipRouteProto value. If this - metric is not used, its value should be set to -1. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteMetric2 { ipRouteEntry 4 } - - Syntax: - INTEGER - - Definition: - An alternate routing metric for this route. The - semantics of this metric are determined by the routing- - protocol specified in the route's ipRouteProto value. If - this metric is not used, its value should be set to -1. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteMetric3 { ipRouteEntry 5 } - - Syntax: - INTEGER - - - - - -McCloghrie & Rose [Page 39] - -RFC 1156 MIB May 1990 - - - Definition: - An alternate routing metric for this route. The - semantics of this metric are determined by the routing- - protocol specified in the route's ipRouteProto value. If - this metric is not used, its value should be set to -1. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteMetric4 { ipRouteEntry 6 } - - Syntax: - INTEGER - - Definition: - An alternate routing metric for this route. The - semantics of this metric are determined by the routing- - protocol specified in the route's ipRouteProto value. If - this metric is not used, its value should be set to -1. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteNextHop { ipRouteEntry 7 } - - Syntax: - IpAddress - - Definition: - The IP address of the next hop of this route. - - Access: - read-write. - - Status: - mandatory. - - - -McCloghrie & Rose [Page 40] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - ipRouteType { ipRouteEntry 8 } - - Syntax: - INTEGER { - other(1), -- none of the following - - invalid(2), -- an invalidated route - - -- route to directly - direct(3), -- connected (sub-)network - - -- route to a non-local - remote(4), -- host/network/sub-network - } - - Definition: - The type of route. - - Access: - read-write. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteProto { ipRouteEntry 9 } - - Syntax: - INTEGER { - other(1), -- none of the following - - -- non-protocol information, - -- e.g., manually configured - local(2), -- entries - - -- set via a network management - netmgmt(3), -- protocol - - -- obtained via ICMP, - icmp(4), -- e.g., Redirect - - -- the remaining values are - -- all gateway routing protocols - egp(5), - - - -McCloghrie & Rose [Page 41] - -RFC 1156 MIB May 1990 - - - ggp(6), - hello(7), - rip(8), - is-is(9), - es-is(10), - ciscoIgrp(11), - bbnSpfIgp(12), - oigp(13) - } - - Definition: - The routing mechanism via which this route was learned. - Inclusion of values for gateway routing protocols is not - intended to imply that hosts should support those - protocols. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - ipRouteAge { ipRouteEntry 10 } - - Syntax: - INTEGER - - Definition: - The number of seconds since this route was last updated - or otherwise determined to be correct. Note that no - semantics of "too old" can be implied except through - knowledge of the routing protocol by which the route was - learned. - - Access: - read-write. - - Status: - mandatory. - - - - - - - - - -McCloghrie & Rose [Page 42] - -RFC 1156 MIB May 1990 - - -5.5. The ICMP Group - - Implementation of the ICMP group is mandatory for all systems. - - The ICMP group contains the ICMP input and output statistics. - - Note that individual counters for ICMP message (sub-)codes have been - omitted from this (version of the) MIB for simplicity. - - - OBJECT: - ------- - icmpInMsgs { icmp 1 } - - Syntax: - Counter - - Definition: - The total number of ICMP messages which the entity - received. Note that this counter includes all those - counted by icmpInErrors. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInErrors { icmp 2 } - - Syntax: - Counter - - Definition: - The number of ICMP messages which the entity received but - determined as having errors (bad ICMP checksums, bad - length, etc.). - - Access: - read-only. - - Status: - mandatory. - - - - - -McCloghrie & Rose [Page 43] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - icmpInDestUnreachs { icmp 3 } - - Syntax: - Counter - - Definition: - The number of ICMP Destination Unreachable messages - received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInTimeExcds { icmp 4 } - - Syntax: - Counter - - Definition: - The number of ICMP Time Exceeded messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInParmProbs { icmp 5 } - - Syntax: - Counter - - Definition: - The number of ICMP Parameter Problem messages received. - - Access: - read-only. - - - - -McCloghrie & Rose [Page 44] - -RFC 1156 MIB May 1990 - - - Status: - mandatory. - - - OBJECT: - ------- - icmpInSrcQuenchs { icmp 6 } - - Syntax: - Counter - - Definition: - The number of ICMP Source Quench messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInRedirects { icmp 7 } - - Syntax: - Counter - - Definition: - The number of ICMP Redirect messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInEchos { icmp 8 } - - Syntax: - Counter - - Definition: - The number of ICMP Echo (request) messages received. - - - - -McCloghrie & Rose [Page 45] - -RFC 1156 MIB May 1990 - - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInEchoReps { icmp 9 } - - Syntax: - Counter - - Definition: - The number of ICMP Echo Reply messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInTimestamps { icmp 10 } - - Syntax: - Counter - - Definition: - The number of ICMP Timestamp (request) messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInTimestampReps { icmp 11 } - - Syntax: - Counter - - - - -McCloghrie & Rose [Page 46] - -RFC 1156 MIB May 1990 - - - Definition: - The number of ICMP Timestamp Reply messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInAddrMasks { icmp 12 } - - Syntax: - Counter - - Definition: - The number of ICMP Address Mask Request messages - received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpInAddrMaskReps { icmp 13 } - - Syntax: - Counter - - Definition: - The number of ICMP Address Mask Reply messages received. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutMsgs { icmp 14 } - - - -McCloghrie & Rose [Page 47] - -RFC 1156 MIB May 1990 - - - Syntax: - Counter - - Definition: - The total number of ICMP messages which this entity - attempted to send. Note that this counter includes all - those counted by icmpOutErrors. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutErrors { icmp 15 } - - Syntax: - Counter - - Definition: - The number of ICMP messages which this entity did not - send due to problems discovered within ICMP such as a - lack of buffers. This value should not include errors - discovered outside the ICMP layer such as the inability - of IP to route the resultant datagram. In some - implementations there may be no types of error which - contribute to this counter's value. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutDestUnreachs { icmp 16 } - - Syntax: - Counter - - Definition: - The number of ICMP Destination Unreachable messages sent. - - - - -McCloghrie & Rose [Page 48] - -RFC 1156 MIB May 1990 - - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutTimeExcds { icmp 17 } - - Syntax: - Counter - - Definition: - The number of ICMP Time Exceeded messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutParmProbs { icmp 18 } - - Syntax: - Counter - - Definition: - The number of ICMP Parameter Problem messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutSrcQuenchs { icmp 19 } - - Syntax: - Counter - - - - -McCloghrie & Rose [Page 49] - -RFC 1156 MIB May 1990 - - - Definition: - The number of ICMP Source Quench messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutRedirects { icmp 20 } - - Syntax: - Counter - - Definition: - The number of ICMP Redirect messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutEchos { icmp 21 } - - Syntax: - Counter - - Definition: - The number of ICMP Echo (request) messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutEchoReps { icmp 22 } - - - - -McCloghrie & Rose [Page 50] - -RFC 1156 MIB May 1990 - - - Syntax: - Counter - - Definition: - The number of ICMP Echo Reply messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutTimestamps { icmp 23 } - - Syntax: - Counter - - Definition: - The number of ICMP Timestamp (request) messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutTimestampReps { icmp 24 } - - Syntax: - Counter - - Definition: - The number of ICMP Timestamp Reply messages sent. - - Access: - read-only. - - Status: - mandatory. - - - - - - -McCloghrie & Rose [Page 51] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - icmpOutAddrMasks { icmp 25 } - - Syntax: - Counter - - Definition: - The number of ICMP Address Mask Request messages sent. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - icmpOutAddrMaskReps { icmp 26 } - - Syntax: - Counter - - Definition: - The number of ICMP Address Mask Reply messages sent. - - Access: - read-only. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 52] - -RFC 1156 MIB May 1990 - - -5.6. The TCP Group - - Implementation of the TCP group is mandatory for all systems - that implement the TCP protocol. - - Note that instances of object types that represent information - about a particular TCP connection are transient; they persist - only as long as the connection in question. - - OBJECT: - ------- - tcpRtoAlgorithm { tcp 1 } - - Syntax: - INTEGER { - other(1), -- none of the following - constant(2), -- a constant rto - rsre(3), -- MIL-STD-1778, Appendix B - vanj(4) -- Van Jacobson's algorithm [15] - } - - Definition: - The algorithm used to determine the timeout value used - for retransmitting unacknowledged octets. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpRtoMin { tcp 2 } - - Syntax: - INTEGER - - Definition: - The minimum value permitted by a TCP implementation - for the retransmission timeout, measured in - milliseconds. More refined semantics for objects - of this type depend upon the algorithm used to - determine the retransmission timeout. In particular, - when the timeout algorithm is rsre(3), an object - of this type has the semantics of the LBOUND - quantity described in RFC 793. - - - -McCloghrie & Rose [Page 53] - -RFC 1156 MIB May 1990 - - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpRtoMax { tcp 3 } - - Syntax: - INTEGER - - Definition: - The maximum value permitted by a TCP implementation - for the retransmission timeout, measured - in milliseconds. More refined semantics for objects - of this type depend upon the algorithm used to - determine the retransmission timeout. In particular, - when the timeout algorithm is rsre(3), an object of - this type has the semantics of the UBOUND quantity - described in RFC 793. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpMaxConn { tcp 4 } - - Syntax: - INTEGER - - Definition: - The limit on the total number of TCP connections the - entity can support. In entities where the maximum - number of connections is dynamic, this object should - contain the value "-1". - - Access: - read-only. - - - - - -McCloghrie & Rose [Page 54] - -RFC 1156 MIB May 1990 - - - Status: - mandatory. - - - OBJECT: - ------- - tcpActiveOpens { tcp 5 } - - Syntax: - Counter - - Definition: - The number of times TCP connections have made a direct - transition to the SYN-SENT state from the CLOSED - state. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpPassiveOpens { tcp 6 } - - Syntax: - Counter - - Definition: - The number of times TCP connections have made a direct - transition to the SYN-RCVD state from the LISTEN - state. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpAttemptFails { tcp 7 } - - Syntax: - Counter - - - -McCloghrie & Rose [Page 55] - -RFC 1156 MIB May 1990 - - - Definition: - The number of times TCP connections have made a direct - transition to the CLOSED state from either the - SYN-SENT state or the SYN-RCVD state, plus the number - of times TCP connections have made a direct transition - to the LISTEN state from the SYN-RCVD state. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpEstabResets { tcp 8 } - - Syntax: - Counter - - Definition: - The number of times TCP connections have made a direct - transition to the CLOSED state from either the - ESTABLISHED state or the CLOSE-WAIT state. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpCurrEstab { tcp 9 } - - Syntax: - Gauge - - Definition: - The number of TCP connections for which the current - state is either ESTABLISHED or CLOSE-WAIT. - - Access: - read-only. - - - - - -McCloghrie & Rose [Page 56] - -RFC 1156 MIB May 1990 - - - Status: - mandatory. - - - OBJECT: - ------- - tcpInSegs { tcp 10 } - - Syntax: - Counter - - Definition: - The total number of segments received, including those - received in error. This count includes segments - received on currently established connections. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpOutSegs { tcp 11 } - - Syntax: - Counter - - Definition: - The total number of segments sent, including those on - current connections but excluding those containing - only retransmitted octets. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpRetransSegs { tcp 12 } - - Syntax: - Counter - - - -McCloghrie & Rose [Page 57] - -RFC 1156 MIB May 1990 - - - Definition: - The total number of segments retransmitted - that is, - the number of TCP segments transmitted containing one - or more previously transmitted octets. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnTable { tcp 13 } - - Syntax: - SEQUENCE OF TcpConnEntry - - Definition: - A table containing TCP connection-specific - information. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnEntry { tcpConnTable 1 } - - Syntax: - TcpConnEntry ::= SEQUENCE { - tcpConnState - INTEGER, - tcpConnLocalAddress - IpAddress, - tcpConnLocalPort - INTEGER (0..65535), - tcpConnRemAddress - IpAddress, - tcpConnRemPort - INTEGER (0..65535) - } - - - - -McCloghrie & Rose [Page 58] - -RFC 1156 MIB May 1990 - - - Definition: - Information about a particular current TCP connection. - An object of this type is transient, in that it ceases - to exist when (or soon after) the connection makes the - transition to the CLOSED state. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnState { tcpConnEntry 1 } - - Syntax: - INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11) - } - - Definition: - The state of this TCP connection. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnLocalAddress { tcpConnEntry 2 } - - Syntax: - IpAddress - - - -McCloghrie & Rose [Page 59] - -RFC 1156 MIB May 1990 - - - Definition: - The local IP address for this TCP connection. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnLocalPort { tcpConnEntry 3 } - - Syntax: - INTEGER (0..65535) - - Definition: - The local port number for this TCP connection. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnRemAddress { tcpConnEntry 4 } - - Syntax: - IpAddress - - Definition: - The remote IP address for this TCP connection. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - tcpConnRemPort { tcpConnEntry 5 } - - - - -McCloghrie & Rose [Page 60] - -RFC 1156 MIB May 1990 - - - Syntax: - INTEGER (0..65535) - - Definition: - The remote port number for this TCP connection. - - Access: - read-only. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 61] - -RFC 1156 MIB May 1990 - - -5.7. The UDP Group - - Implementation of the UDP group is mandatory for all systems - which implement the UDP protocol. - - OBJECT: - ------- - udpInDatagrams { udp 1 } - - Syntax: - Counter - - Definition: - The total number of UDP datagrams delivered to UDP - users. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - udpNoPorts { udp 2 } - - Syntax: - Counter - - Definition: - The total number of received UDP datagrams for which - there was no application at the destination port. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - udpInErrors { udp 3 } - - Syntax: - Counter - - - - -McCloghrie & Rose [Page 62] - -RFC 1156 MIB May 1990 - - - Definition: - The number of received UDP datagrams that could not be - delivered for reasons other than the lack of an - application at the destination port. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - udpOutDatagrams { udp 4 } - - Syntax: - Counter - - Definition: - The total number of UDP datagrams sent from this - entity. - - Access: - read-only. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 63] - -RFC 1156 MIB May 1990 - - -5.8. The EGP Group - - Implementation of the EGP group is mandatory for all systems - which implement the EGP protocol. - - OBJECT: - ------- - egpInMsgs { egp 1 } - - Syntax: - Counter - - Definition: - The number of EGP messages received without error. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - egpInErrors { egp 2 } - - Syntax: - Counter - - Definition: - The number of EGP messages received that proved to be - in error. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - egpOutMsgs { egp 3 } - - Syntax: - Counter - - - - - -McCloghrie & Rose [Page 64] - -RFC 1156 MIB May 1990 - - - Definition: - The total number of locally generated EGP messages. - - Access: - read-only. - - Status: - mandatory. - - - OBJECT: - ------- - egpOutErrors { egp 4 } - - Syntax: - Counter - - Definition: - The number of locally generated EGP messages not sent - due to resource limitations within an EGP entity. - - Access: - read-only. - - Status: - mandatory. - -5.8.1. The EGP Neighbor Table - - The Egp Neighbor table contains information about this entity's EGP - neighbors. - - - OBJECT: - ------- - egpNeighTable { egp 5 } - - Syntax: - SEQUENCE OF EgpNeighEntry - - Definition: - The EGP neighbor table. - - Access: - read-only. - - Status: - mandatory. - - - -McCloghrie & Rose [Page 65] - -RFC 1156 MIB May 1990 - - - OBJECT: - ------- - egpNeighEntry { egpNeighTable 1 } - - Syntax: - EgpNeighEntry ::= SEQUENCE { - egpNeighState - INTEGER, - egpNeighAddr - IpAddress - } - - Definition: - Information about this entity's relationship with a - particular EGP neighbor. - - Access: - read-only. - - Status: - mandatory. - - - We now consider the individual components of each EGP - neighbor entry: - - - OBJECT: - ------- - egpNeighState { egpNeighEntry 1 } - - Syntax: - INTEGER { - idle(1), - acquisition(2), - down(3), - up(4), - cease(5) - } - - Definition: - The EGP state of the local system with respect to this - entry's EGP neighbor. Each EGP state is represented - by a value that is one greater than the numerical - value associated with said state in RFC 904. - - Access: - read-only. - - - -McCloghrie & Rose [Page 66] - -RFC 1156 MIB May 1990 - - - Status: - mandatory. - - - OBJECT: - ------- - egpNeighAddr { egpNeighEntry 2 } - - Syntax: - IpAddress - - Definition: - The IP address of this entry's EGP neighbor. - - Access: - read-only. - - Status: - mandatory. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 67] - -RFC 1156 MIB May 1990 - - -6. Definitions - - RFC1156-MIB - - DEFINITIONS ::= BEGIN - - IMPORTS - mgmt, OBJECT-TYPE, NetworkAddress, IpAddress, - Counter, Gauge, TimeTicks - FROM RFC1155-SMI; - - mib OBJECT IDENTIFIER ::= { mgmt 1 } - - system OBJECT IDENTIFIER ::= { mib 1 } - interfaces OBJECT IDENTIFIER ::= { mib 2 } - at OBJECT IDENTIFIER ::= { mib 3 } - ip OBJECT IDENTIFIER ::= { mib 4 } - icmp OBJECT IDENTIFIER ::= { mib 5 } - tcp OBJECT IDENTIFIER ::= { mib 6 } - udp OBJECT IDENTIFIER ::= { mib 7 } - egp OBJECT IDENTIFIER ::= { mib 8 } - - -- object types - - -- the System group - - sysDescr OBJECT-TYPE - SYNTAX OCTET STRING - ACCESS read-only - STATUS mandatory - ::= { system 1 } - - sysObjectID OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - ACCESS read-only - STATUS mandatory - ::= { system 2 } - - sysUpTime OBJECT-TYPE - SYNTAX TimeTicks - ACCESS read-only - STATUS mandatory - ::= { system 3 } - - -- the Interfaces group - - ifNumber OBJECT-TYPE - SYNTAX INTEGER - - - -McCloghrie & Rose [Page 68] - -RFC 1156 MIB May 1990 - - - ACCESS read-only - STATUS mandatory - ::= { interfaces 1 } - - -- the Interfaces table - - ifTable OBJECT-TYPE - SYNTAX SEQUENCE OF IfEntry - ACCESS read-write - STATUS mandatory - ::= { interfaces 2 } - - ifEntry OBJECT-TYPE - SYNTAX IfEntry - ACCESS read-write - STATUS mandatory - ::= { ifTable 1 } - - IfEntry ::= SEQUENCE { - ifIndex - INTEGER, - ifDescr - OCTET STRING, - ifType - INTEGER, - ifMtu - INTEGER, - ifSpeed - Gauge, - ifPhysAddress - OCTET STRING, - ifAdminStatus - INTEGER, - ifOperStatus - INTEGER, - ifLastChange - TimeTicks, - ifInOctets - Counter, - ifInUcastPkts - Counter, - ifInNUcastPkts - Counter, - ifInDiscards - Counter, - ifInErrors - Counter, - ifInUnknownProtos - - - -McCloghrie & Rose [Page 69] - -RFC 1156 MIB May 1990 - - - Counter, - ifOutOctets - Counter, - ifOutUcastPkts - Counter, - ifOutNUcastPkts - Counter, - ifOutDiscards - Counter, - ifOutErrors - Counter, - ifOutQLen - Gauge - } - - ifIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { ifEntry 1 } - - ifDescr OBJECT-TYPE - SYNTAX OCTET STRING - ACCESS read-only - STATUS mandatory - ::= { ifEntry 2 } - - ifType OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - regular1822(2), - hdh1822(3), - ddn-x25(4), - rfc877-x25(5), - ethernet-csmacd(6), - iso88023-csmacd(7), - iso88024-tokenBus(8), - iso88025-tokenRing(9), - iso88026-man(10), - starLan(11), - proteon-10MBit(12), - proteon-80MBit(13), - hyperchannel(14), - fddi(15), - lapb(16), - sdlc(17), - t1-carrier(18), - cept(19), - - - -McCloghrie & Rose [Page 70] - -RFC 1156 MIB May 1990 - - - basicIsdn(20), - primaryIsdn(21), - -- proprietary serial - propPointToPointSerial(22) - } - ACCESS read-only - STATUS mandatory - ::= { ifEntry 3 } - - ifMtu OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { ifEntry 4 } - - ifSpeed OBJECT-TYPE - SYNTAX Gauge - ACCESS read-only - STATUS mandatory - ::= { ifEntry 5 } - - ifPhysAddress OBJECT-TYPE - SYNTAX OCTET STRING - ACCESS read-only - STATUS mandatory - ::= { ifEntry 6 } - - ifAdminStatus OBJECT-TYPE - SYNTAX INTEGER { - up(1), -- ready to pass packets - down(2), - testing(3) -- in some test mode - } - ACCESS read-write - STATUS mandatory - ::= { ifEntry 7 } - - ifOperStatus OBJECT-TYPE - SYNTAX INTEGER { - up(1), -- ready to pass packets - down(2), - testing(3) -- in some test mode - } - ACCESS read-only - STATUS mandatory - ::= { ifEntry 8 } - - ifLastChange OBJECT-TYPE - - - -McCloghrie & Rose [Page 71] - -RFC 1156 MIB May 1990 - - - SYNTAX TimeTicks - ACCESS read-only - STATUS mandatory - ::= { ifEntry 9 } - - ifInOctets OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 10 } - - ifInUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 11 } - - ifInNUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 12 } - - ifInDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 13 } - - ifInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 14 } - - ifInUnknownProtos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 15 } - - ifOutOctets OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 16 } - - ifOutUcastPkts OBJECT-TYPE - - - -McCloghrie & Rose [Page 72] - -RFC 1156 MIB May 1990 - - - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 17 } - - ifOutNUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 18 } - - ifOutDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 19 } - - ifOutErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ifEntry 20 } - - ifOutQLen OBJECT-TYPE - SYNTAX Gauge - ACCESS read-only - STATUS mandatory - ::= { ifEntry 21 } - - -- the Address Translation group - - atTable OBJECT-TYPE - SYNTAX SEQUENCE OF AtEntry - ACCESS read-write - STATUS mandatory - ::= { at 1 } - - atEntry OBJECT-TYPE - SYNTAX AtEntry - ACCESS read-write - STATUS mandatory - ::= { atTable 1 } - - AtEntry ::= SEQUENCE { - atIfIndex - INTEGER, - atPhysAddress - OCTET STRING, - - - -McCloghrie & Rose [Page 73] - -RFC 1156 MIB May 1990 - - - atNetAddress - NetworkAddress - } - - atIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { atEntry 1 } - - atPhysAddress OBJECT-TYPE - SYNTAX OCTET STRING - ACCESS read-write - STATUS mandatory - ::= { atEntry 2 } - - atNetAddress OBJECT-TYPE - SYNTAX NetworkAddress - ACCESS read-write - STATUS mandatory - ::= { atEntry 3 } - - -- the IP group - - ipForwarding OBJECT-TYPE - SYNTAX INTEGER { - gateway(1), -- entity forwards datagrams - host(2) -- entity does NOT forward datagrams - } - ACCESS read-only - STATUS mandatory - ::= { ip 1 } - - ipDefaultTTL OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ip 2 } - - ipInReceives OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 3 } - - ipInHdrErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - - - -McCloghrie & Rose [Page 74] - -RFC 1156 MIB May 1990 - - - STATUS mandatory - ::= { ip 4 } - - ipInAddrErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 5 } - - ipForwDatagrams OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 6 } - - ipInUnknownProtos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 7 } - - ipInDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 8 } - - ipInDelivers OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 9 } - - ipOutRequests OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 10 } - - ipOutDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 11 } - - ipOutNoRoutes OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - - - -McCloghrie & Rose [Page 75] - -RFC 1156 MIB May 1990 - - - STATUS mandatory - ::= { ip 12 } - - ipReasmTimeout OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { ip 13 } - - ipReasmReqds OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 14 } - - ipReasmOKs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 15 } - - ipReasmFails OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 16 } - - ipFragOKs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 17 } - - ipFragFails OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 18 } - - ipFragCreates OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { ip 19 } - - -- the IP Interface table - - ipAddrTable OBJECT-TYPE - - - -McCloghrie & Rose [Page 76] - -RFC 1156 MIB May 1990 - - - SYNTAX SEQUENCE OF IpAddrEntry - ACCESS read-only - STATUS mandatory - ::= { ip 20 } - - ipAddrEntry OBJECT-TYPE - SYNTAX IpAddrEntry - ACCESS read-only - STATUS mandatory - ::= { ipAddrTable 1 } - - IpAddrEntry ::= SEQUENCE { - ipAdEntAddr - IpAddress, - ipAdEntIfIndex - INTEGER, - ipAdEntNetMask - IpAddress, - ipAdEntBcastAddr - INTEGER - } - - ipAdEntAddr OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - ::= { ipAddrEntry 1 } - - ipAdEntIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { ipAddrEntry 2 } - - ipAdEntNetMask OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - ::= { ipAddrEntry 3 } - - ipAdEntBcastAddr OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { ipAddrEntry 4 } - - - - - - -McCloghrie & Rose [Page 77] - -RFC 1156 MIB May 1990 - - - -- the IP Routing table - - ipRoutingTable OBJECT-TYPE - SYNTAX SEQUENCE OF IpRouteEntry - ACCESS read-write - STATUS mandatory - ::= { ip 21 } - - ipRouteEntry OBJECT-TYPE - SYNTAX IpRouteEntry - ACCESS read-write - STATUS mandatory - ::= { ipRoutingTable 1 } - - IpRouteEntry ::= SEQUENCE { - ipRouteDest - IpAddress, - ipRouteIfIndex - INTEGER, - ipRouteMetric1 - INTEGER, - ipRouteMetric2 - INTEGER, - ipRouteMetric3 - INTEGER, - ipRouteMetric4 - INTEGER, - ipRouteNextHop - IpAddress, - ipRouteType - INTEGER, - ipRouteProto - INTEGER, - ipRouteAge - INTEGER - } - - ipRouteDest OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 1 } - - ipRouteIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 2 } - - - -McCloghrie & Rose [Page 78] - -RFC 1156 MIB May 1990 - - - ipRouteMetric1 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 3 } - - ipRouteMetric2 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 4 } - - ipRouteMetric3 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 5 } - - ipRouteMetric4 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 6 } - - ipRouteNextHop OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 7 } - - ipRouteType OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - - invalid(2), -- an invalidated route - - -- route to directly - direct(3), -- connected (sub-)network - - -- route to a non-local - remote(4), -- host/network/sub-network - } - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 8 } - - ipRouteProto OBJECT-TYPE - SYNTAX INTEGER { - - - -McCloghrie & Rose [Page 79] - -RFC 1156 MIB May 1990 - - - other(1), -- none of the following - - -- non-protocol information - -- e.g., manually - local(2), -- configured entries - - -- set via a network - netmgmt(3), -- management protocol - - -- obtained via ICMP, - icmp(4), -- e.g., Redirect - - -- the following are - -- gateway routing protocols - egp(5), - ggp(6), - hello(7), - rip(8), - is-is(9), - es-is(10), - ciscoIgrp(11), - bbnSpfIgp(12), - oigp(13) - } - ACCESS read-only - STATUS mandatory - ::= { ipRouteEntry 9 } - - ipRouteAge OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - ::= { ipRouteEntry 10 } - - -- the ICMP group - - icmpInMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 1 } - - icmpInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 2 } - - - - -McCloghrie & Rose [Page 80] - -RFC 1156 MIB May 1990 - - - icmpInDestUnreachs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 3 } - - icmpInTimeExcds OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 4 } - - icmpInParmProbs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 5 } - - icmpInSrcQuenchs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 6 } - - icmpInRedirects OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 7 } - - icmpInEchos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 8 } - - icmpInEchoReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 9 } - - icmpInTimestamps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 10 } - - - - -McCloghrie & Rose [Page 81] - -RFC 1156 MIB May 1990 - - - icmpInTimestampReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 11 } - - icmpInAddrMasks OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 12 } - - icmpInAddrMaskReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 13 } - - icmpOutMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 14 } - - icmpOutErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 15 } - - icmpOutDestUnreachs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 16 } - - icmpOutTimeExcds OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 17 } - - icmpOutParmProbs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 18 } - - - - -McCloghrie & Rose [Page 82] - -RFC 1156 MIB May 1990 - - - icmpOutSrcQuenchs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 19 } - - icmpOutRedirects OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 20 } - - icmpOutEchos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 21 } - - icmpOutEchoReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 22 } - - icmpOutTimestamps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 23 } - - icmpOutTimestampReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 24 } - - icmpOutAddrMasks OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 25 } - - icmpOutAddrMaskReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { icmp 26 } - - - - -McCloghrie & Rose [Page 83] - -RFC 1156 MIB May 1990 - - - -- the TCP group - - tcpRtoAlgorithm OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - constant(2), -- a constant rto - rsre(3), -- MIL-STD-1778, Appendix B - vanj(4) -- Van Jacobson's algorithm [15] - } - ACCESS read-only - STATUS mandatory - ::= { tcp 1 } - - tcpRtoMin OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { tcp 2 } - - tcpRtoMax OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { tcp 3 } - - tcpMaxConn OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - ::= { tcp 4 } - - tcpActiveOpens OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 5 } - - tcpPassiveOpens OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 6 } - - tcpAttemptFails OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 7 } - - - -McCloghrie & Rose [Page 84] - -RFC 1156 MIB May 1990 - - - tcpEstabResets OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 8 } - - tcpCurrEstab OBJECT-TYPE - SYNTAX Gauge - ACCESS read-only - STATUS mandatory - ::= { tcp 9 } - - tcpInSegs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 10 } - - tcpOutSegs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 11 } - - tcpRetransSegs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { tcp 12 } - - -- the TCP connections table - - tcpConnTable OBJECT-TYPE - SYNTAX SEQUENCE OF TcpConnEntry - ACCESS read-only - STATUS mandatory - ::= { tcp 13 } - - tcpConnEntry OBJECT-TYPE - SYNTAX TcpConnEntry - ACCESS read-only - STATUS mandatory - ::= { tcpConnTable 1 } - - TcpConnEntry ::= SEQUENCE { - tcpConnState - INTEGER, - tcpConnLocalAddress - - - -McCloghrie & Rose [Page 85] - -RFC 1156 MIB May 1990 - - - IpAddress, - tcpConnLocalPort - INTEGER (0..65535), - tcpConnRemAddress - IpAddress, - tcpConnRemPort - INTEGER (0..65535) - } - - tcpConnState OBJECT-TYPE - SYNTAX INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11) - } - ACCESS read-only - STATUS mandatory - ::= { tcpConnEntry 1 } - - tcpConnLocalAddress OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - ::= { tcpConnEntry 2 } - - tcpConnLocalPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - ACCESS read-only - STATUS mandatory - ::= { tcpConnEntry 3 } - - tcpConnRemAddress OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - ::= { tcpConnEntry 4 } - - tcpConnRemPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - ACCESS read-only - - - -McCloghrie & Rose [Page 86] - -RFC 1156 MIB May 1990 - - - STATUS mandatory - ::= { tcpConnEntry 5 } - - -- the UDP group - - udpInDatagrams OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { udp 1 } - - udpNoPorts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { udp 2 } - - udpInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { udp 3 } - - udpOutDatagrams OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { udp 4 } - - -- the EGP group - - egpInMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { egp 1 } - - egpInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { egp 2 } - - egpOutMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { egp 3 } - - - -McCloghrie & Rose [Page 87] - -RFC 1156 MIB May 1990 - - - egpOutErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - ::= { egp 4 } - - -- the EGP Neighbor table - - egpNeighTable OBJECT-TYPE - SYNTAX SEQUENCE OF EgpNeighEntry - ACCESS read-only - STATUS mandatory - ::= { egp 5 } - - egpNeighEntry OBJECT-TYPE - SYNTAX EgpNeighEntry - ACCESS read-only - STATUS mandatory - ::= { egpNeighTable 1 } - - EgpNeighEntry ::= SEQUENCE { - egpNeighState - INTEGER, - egpNeighAddr - IpAddress - } - - egpNeighState OBJECT-TYPE - SYNTAX INTEGER { - idle(1), - acquisition(2), - down(3), - up(4), - cease(5) - } - ACCESS read-only - STATUS mandatory - ::= { egpNeighEntry 1 } - - egpNeighAddr OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - ::= { egpNeighEntry 2 } - - END - - - - - -McCloghrie & Rose [Page 88] - -RFC 1156 MIB May 1990 - - -7. Acknowledgements - - The initial draft of this memo was heavily influenced by the the HEMS - [9] and SNMP [10] MIBs. - - Its final form is the result of the suggestions, the dicussions, and - the compromises reached by the members of the IETF MIB working group: - - Karl Auerbach, Epilogue Technology - K. Ramesh Babu, Excelan - Lawrence Besaw, Hewlett-Packard - Jeffrey D. Case, University of Tennessee at Knoxville - James R. Davin, Proteon - Mark S. Fedor, NYSERNet - Robb Foster, BBN - Phill Gross, The MITRE Corporation - Bent Torp Jensen, Convergent Technology - Lee Labarre, The MITRE Corporation - Dan Lynch, Advanced Computing Environments - Keith McCloghrie, The Wollongong Group - Dave Mackie, 3Com/Bridge - Craig Partridge, BBN (chair) - Jim Robertson, 3Com/Bridge - Marshall T. Rose, The Wollongong Group - Greg Satz, cisco - Martin Lee Schoffstall, Rensselaer Polytechnic Institute - Lou Steinberg, IBM - Dean Throop, Data General - Unni Warrier, Unisys - - - - - - - - - - - - - - - - - - - - - - -McCloghrie & Rose [Page 89] - -RFC 1156 MIB May 1990 - - -8. References - - [1] Cerf, V., "IAB Recommendations for the Development of Internet - Network Management Standards", RFC 1052, IAB, April 1988. - - [2] Information processing systems - Open Systems Interconnection, - "Management Information Services Definition", International - Organization for Standardization, Draft Proposal 9595/2, - December 1987. - - [3] Information processing systems - Open Systems Interconnection, - "Management Information Protocol Specification", International - Organization for Standardization, Draft Proposal 9596/2, - December 1987. - - [4] Rose M., and K. McCloghrie, "Structure and Identification of - Management Information for TCP/IP-based internets", RFC 1065, - TWG, August 1988. - - [5] Partridge C., and G. Trewitt, "The High-Level Entity Management - System (HEMS)", RFCs 1021-1024, BBN and Stanford, October 1987. - - [6] Cerf, V., "Report of the Second Ad Hoc Network Management Review - Group", RFC 1109, IAB, August 1989. - - [7] Rose, M., and K. McCloghrie, "Structure and Identification of - Management Information for TCP/IP-based Internets", RFC 1155, - Performance Systems International and Hughes LAN Systems, May - 1990. - - [8] Case, J., M. Fedor, M. Schoffstall, and J. Davin, The Simple - Network Management Protocol", RFC 1157, University of Tennessee - at Knoxville, Performance Systems International, Performance - Systems International, and the MIT Laboratory for Computer - Science, May 1990. - - [9] Partridge C., and G. Trewitt, "HEMS Variable Definitions", RFC - 1024, BBN and Stanford, October 1987. - - [10] Case, J., M. Fedor, M. Schoffstall, and J. Davin, "A Simple - Network Management Protocol", RFC 1067, University of Tennessee - At Knoxville, NYSERNet, Rensselaer Polytechnic, Proteon, August - 1988. - - [11] LaBarre, L., "Structure and Identification of Management - Information for the Internet", Internet Engineering Task Force - working note, Network Information Center, SRI International, - Menlo Park, California, April 1988. - - - -McCloghrie & Rose [Page 90] - -RFC 1156 MIB May 1990 - - - [12] LaBarre, L., "Transport Layer Management Information: TCP", - Internet Engineering Task Force working note in preparation. - Network Information Center, SRI International, Menlo Park, - California, (unpublished). - - [13] Information processing systems - Open Systems Interconnection, - "Specification of Abstract Syntax Notation One (ASN.1)", - International Organization for Standardization, International - Standard 8824, December 1987. - - [14] Information processing systems - Open Systems Interconnection, - "Specification of Basic Encoding Rules for Abstract Notation One - (ASN.1)", International Organization for Standardization, - International Standard 8825, December 1987. - - [15] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM, 1988, - Stanford, California. - -Security Considerations - - Security issues are not discussed in this memo. - -Authors' Addresses - - Keith McCloghrie - The Wollongong Group - 1129 San Antonio Road - Palo Alto, CA 04303 - - Phone: (415) 962-7160 - - EMail: sytek!kzm@HPLABS.HP.COM - - - Marshall T. Rose - PSI, Inc. - PSI California Office - P.O. Box 391776 - Mountain View, CA 94039 - - Phone: (415) 961-3380 - - EMail: mrose@PSI.COM - - - - - - - - -McCloghrie & Rose [Page 91] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1180.txt b/ext/picotcp/RFC/rfc1180.txt deleted file mode 100644 index 6bbb6d9..0000000 --- a/ext/picotcp/RFC/rfc1180.txt +++ /dev/null @@ -1,1571 +0,0 @@ - - - - - - -Network Working Group T. Socolofsky -Request for Comments: 1180 C. Kale - Spider Systems Limited - January 1991 - - - A TCP/IP Tutorial - -Status of this Memo - - This RFC is a tutorial on the TCP/IP protocol suite, focusing - particularly on the steps in forwarding an IP datagram from source - host to destination host through a router. It does not specify an - Internet standard. Distribution of this memo is unlimited. - -Table of Contents - - 1. Introduction................................................ 1 - 2. TCP/IP Overview............................................. 2 - 3. Ethernet.................................................... 8 - 4. ARP......................................................... 9 - 5. Internet Protocol........................................... 12 - 6. User Datagram Protocol...................................... 22 - 7. Transmission Control Protocol............................... 24 - 8. Network Applications........................................ 25 - 9. Other Information........................................... 27 - 10. References.................................................. 27 - 11. Relation to other RFCs...................................... 27 - 12. Security Considerations..................................... 27 - 13. Authors' Addresses.......................................... 28 - -1. Introduction - - This tutorial contains only one view of the salient points of TCP/IP, - and therefore it is the "bare bones" of TCP/IP technology. It omits - the history of development and funding, the business case for its - use, and its future as compared to ISO OSI. Indeed, a great deal of - technical information is also omitted. What remains is a minimum of - information that must be understood by the professional working in a - TCP/IP environment. These professionals include the systems - administrator, the systems programmer, and the network manager. - - This tutorial uses examples from the UNIX TCP/IP environment, however - the main points apply across all implementations of TCP/IP. - - Note that the purpose of this memo is explanation, not definition. - If any question arises about the correct specification of a protocol, - please refer to the actual standards defining RFC. - - - -Socolofsky & Kale [Page 1] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - The next section is an overview of TCP/IP, followed by detailed - descriptions of individual components. - -2. TCP/IP Overview - - The generic term "TCP/IP" usually means anything and everything - related to the specific protocols of TCP and IP. It can include - other protocols, applications, and even the network medium. A sample - of these protocols are: UDP, ARP, and ICMP. A sample of these - applications are: TELNET, FTP, and rcp. A more accurate term is - "internet technology". A network that uses internet technology is - called an "internet". - -2.1 Basic Structure - - To understand this technology you must first understand the following - logical structure: - - ---------------------------- - | network applications | - | | - |... \ | / .. \ | / ...| - | ----- ----- | - | |TCP| |UDP| | - | ----- ----- | - | \ / | - | -------- | - | | IP | | - | ----- -*------ | - | |ARP| | | - | ----- | | - | \ | | - | ------ | - | |ENET| | - | ---@-- | - ----------|----------------- - | - ----------------------o--------- - Ethernet Cable - - Figure 1. Basic TCP/IP Network Node - - This is the logical structure of the layered protocols inside a - computer on an internet. Each computer that can communicate using - internet technology has such a logical structure. It is this logical - structure that determines the behavior of the computer on the - internet. The boxes represent processing of the data as it passes - through the computer, and the lines connecting boxes show the path of - - - -Socolofsky & Kale [Page 2] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - data. The horizontal line at the bottom represents the Ethernet - cable; the "o" is the transceiver. The "*" is the IP address and the - "@" is the Ethernet address. Understanding this logical structure is - essential to understanding internet technology; it is referred to - throughout this tutorial. - -2.2 Terminology - - The name of a unit of data that flows through an internet is - dependent upon where it exists in the protocol stack. In summary: if - it is on an Ethernet it is called an Ethernet frame; if it is between - the Ethernet driver and the IP module it is called a IP packet; if it - is between the IP module and the UDP module it is called a UDP - datagram; if it is between the IP module and the TCP module it is - called a TCP segment (more generally, a transport message); and if it - is in a network application it is called a application message. - - These definitions are imperfect. Actual definitions vary from one - publication to the next. More specific definitions can be found in - RFC 1122, section 1.3.3. - - A driver is software that communicates directly with the network - interface hardware. A module is software that communicates with a - driver, with network applications, or with another module. - - The terms driver, module, Ethernet frame, IP packet, UDP datagram, - TCP message, and application message are used where appropriate - throughout this tutorial. - -2.3 Flow of Data - - Let's follow the data as it flows down through the protocol stack - shown in Figure 1. For an application that uses TCP (Transmission - Control Protocol), data passes between the application and the TCP - module. For applications that use UDP (User Datagram Protocol), data - passes between the application and the UDP module. FTP (File - Transfer Protocol) is a typical application that uses TCP. Its - protocol stack in this example is FTP/TCP/IP/ENET. SNMP (Simple - Network Management Protocol) is an application that uses UDP. Its - protocol stack in this example is SNMP/UDP/IP/ENET. - - The TCP module, UDP module, and the Ethernet driver are n-to-1 - multiplexers. As multiplexers they switch many inputs to one output. - They are also 1-to-n de-multiplexers. As de-multiplexers they switch - one input to many outputs according to the type field in the protocol - header. - - - - - -Socolofsky & Kale [Page 3] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - 1 2 3 ... n 1 2 3 ... n - \ | / | \ | | / ^ - \ | | / | \ | | / | - ------------- flow ---------------- flow - |multiplexer| of |de-multiplexer| of - ------------- data ---------------- data - | | | | - | v | | - 1 1 - - Figure 2. n-to-1 multiplexer and 1-to-n de-multiplexer - - If an Ethernet frame comes up into the Ethernet driver off the - network, the packet can be passed upwards to either the ARP (Address - Resolution Protocol) module or to the IP (Internet Protocol) module. - The value of the type field in the Ethernet frame determines whether - the Ethernet frame is passed to the ARP or the IP module. - - If an IP packet comes up into IP, the unit of data is passed upwards - to either TCP or UDP, as determined by the value of the protocol - field in the IP header. - - If the UDP datagram comes up into UDP, the application message is - passed upwards to the network application based on the value of the - port field in the UDP header. If the TCP message comes up into TCP, - the application message is passed upwards to the network application - based on the value of the port field in the TCP header. - - The downwards multiplexing is simple to perform because from each - starting point there is only the one downward path; each protocol - module adds its header information so the packet can be de- - multiplexed at the destination computer. - - Data passing out from the applications through either TCP or UDP - converges on the IP module and is sent downwards through the lower - network interface driver. - - Although internet technology supports many different network media, - Ethernet is used for all examples in this tutorial because it is the - most common physical network used under IP. The computer in Figure 1 - has a single Ethernet connection. The 6-byte Ethernet address is - unique for each interface on an Ethernet and is located at the lower - interface of the Ethernet driver. - - The computer also has a 4-byte IP address. This address is located - at the lower interface to the IP module. The IP address must be - unique for an internet. - - - - -Socolofsky & Kale [Page 4] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - A running computer always knows its own IP address and Ethernet - address. - -2.4 Two Network Interfaces - - If a computer is connected to 2 separate Ethernets it is as in Figure - 3. - - ---------------------------- - | network applications | - | | - |... \ | / .. \ | / ...| - | ----- ----- | - | |TCP| |UDP| | - | ----- ----- | - | \ / | - | -------- | - | | IP | | - | ----- -*----*- ----- | - | |ARP| | | |ARP| | - | ----- | | ----- | - | \ | | / | - | ------ ------ | - | |ENET| |ENET| | - | ---@-- ---@-- | - ----------|-------|--------- - | | - | ---o--------------------------- - | Ethernet Cable 2 - ---------------o---------- - Ethernet Cable 1 - - Figure 3. TCP/IP Network Node on 2 Ethernets - - Please note that this computer has 2 Ethernet addresses and 2 IP - addresses. - - It is seen from this structure that for computers with more than one - physical network interface, the IP module is both a n-to-m - multiplexer and an m-to-n de-multiplexer. - - - - - - - - - - - -Socolofsky & Kale [Page 5] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - 1 2 3 ... n 1 2 3 ... n - \ | | / | \ | | / ^ - \ | | / | \ | | / | - ------------- flow ---------------- flow - |multiplexer| of |de-multiplexer| of - ------------- data ---------------- data - / | | \ | / | | \ | - / | | \ v / | | \ | - 1 2 3 ... m 1 2 3 ... m - - Figure 4. n-to-m multiplexer and m-to-n de-multiplexer - - It performs this multiplexing in either direction to accommodate - incoming and outgoing data. An IP module with more than 1 network - interface is more complex than our original example in that it can - forward data onto the next network. Data can arrive on any network - interface and be sent out on any other. - - TCP UDP - \ / - \ / - -------------- - | IP | - | | - | --- | - | / \ | - | / v | - -------------- - / \ - / \ - data data - comes in goes out - here here - - Figure 5. Example of IP Forwarding a IP Packet - - The process of sending an IP packet out onto another network is - called "forwarding" an IP packet. A computer that has been dedicated - to the task of forwarding IP packets is called an "IP-router". - - As you can see from the figure, the forwarded IP packet never touches - the TCP and UDP modules on the IP-router. Some IP-router - implementations do not have a TCP or UDP module. - -2.5 IP Creates a Single Logical Network - - The IP module is central to the success of internet technology. Each - module or driver adds its header to the message as the message passes - - - -Socolofsky & Kale [Page 6] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - down through the protocol stack. Each module or driver strips the - corresponding header from the message as the message climbs the - protocol stack up towards the application. The IP header contains - the IP address, which builds a single logical network from multiple - physical networks. This interconnection of physical networks is the - source of the name: internet. A set of interconnected physical - networks that limit the range of an IP packet is called an - "internet". - -2.6 Physical Network Independence - - IP hides the underlying network hardware from the network - applications. If you invent a new physical network, you can put it - into service by implementing a new driver that connects to the - internet underneath IP. Thus, the network applications remain intact - and are not vulnerable to changes in hardware technology. - -2.7 Interoperability - - If two computers on an internet can communicate, they are said to - "interoperate"; if an implementation of internet technology is good, - it is said to have "interoperability". Users of general-purpose - computers benefit from the installation of an internet because of the - interoperability in computers on the market. Generally, when you buy - a computer, it will interoperate. If the computer does not have - interoperability, and interoperability can not be added, it occupies - a rare and special niche in the market. - -2.8 After the Overview - - With the background set, we will answer the following questions: - - When sending out an IP packet, how is the destination Ethernet - address determined? - - How does IP know which of multiple lower network interfaces to use - when sending out an IP packet? - - How does a client on one computer reach the server on another? - - Why do both TCP and UDP exist, instead of just one or the other? - - What network applications are available? - - These will be explained, in turn, after an Ethernet refresher. - - - - - - -Socolofsky & Kale [Page 7] - -RFC 1180 A TCP/IP Tutorial January 1991 - - -3. Ethernet - - This section is a short review of Ethernet technology. - - An Ethernet frame contains the destination address, source address, - type field, and data. - - An Ethernet address is 6 bytes. Every device has its own Ethernet - address and listens for Ethernet frames with that destination - address. All devices also listen for Ethernet frames with a wild- - card destination address of "FF-FF-FF-FF-FF-FF" (in hexadecimal), - called a "broadcast" address. - - Ethernet uses CSMA/CD (Carrier Sense and Multiple Access with - Collision Detection). CSMA/CD means that all devices communicate on - a single medium, that only one can transmit at a time, and that they - can all receive simultaneously. If 2 devices try to transmit at the - same instant, the transmit collision is detected, and both devices - wait a random (but short) period before trying to transmit again. - -3.1 A Human Analogy - - A good analogy of Ethernet technology is a group of people talking in - a small, completely dark room. In this analogy, the physical network - medium is sound waves on air in the room instead of electrical - signals on a coaxial cable. - - Each person can hear the words when another is talking (Carrier - Sense). Everyone in the room has equal capability to talk (Multiple - Access), but none of them give lengthy speeches because they are - polite. If a person is impolite, he is asked to leave the room - (i.e., thrown off the net). - - No one talks while another is speaking. But if two people start - speaking at the same instant, each of them know this because each - hears something they haven't said (Collision Detection). When these - two people notice this condition, they wait for a moment, then one - begins talking. The other hears the talking and waits for the first - to finish before beginning his own speech. - - Each person has an unique name (unique Ethernet address) to avoid - confusion. Every time one of them talks, he prefaces the message - with the name of the person he is talking to and with his own name - (Ethernet destination and source address, respectively), i.e., "Hello - Jane, this is Jack, ..blah blah blah...". If the sender wants to - talk to everyone he might say "everyone" (broadcast address), i.e., - "Hello Everyone, this is Jack, ..blah blah blah...". - - - - -Socolofsky & Kale [Page 8] - -RFC 1180 A TCP/IP Tutorial January 1991 - - -4. ARP - - When sending out an IP packet, how is the destination Ethernet - address determined? - - ARP (Address Resolution Protocol) is used to translate IP addresses - to Ethernet addresses. The translation is done only for outgoing IP - packets, because this is when the IP header and the Ethernet header - are created. - -4.1 ARP Table for Address Translation - - The translation is performed with a table look-up. The table, called - the ARP table, is stored in memory and contains a row for each - computer. There is a column for IP address and a column for Ethernet - address. When translating an IP address to an Ethernet address, the - table is searched for a matching IP address. The following is a - simplified ARP table: - - ------------------------------------ - |IP address Ethernet address | - ------------------------------------ - |223.1.2.1 08-00-39-00-2F-C3| - |223.1.2.3 08-00-5A-21-A7-22| - |223.1.2.4 08-00-10-99-AC-54| - ------------------------------------ - TABLE 1. Example ARP Table - - The human convention when writing out the 4-byte IP address is each - byte in decimal and separating bytes with a period. When writing out - the 6-byte Ethernet address, the conventions are each byte in - hexadecimal and separating bytes with either a minus sign or a colon. - - The ARP table is necessary because the IP address and Ethernet - address are selected independently; you can not use an algorithm to - translate IP address to Ethernet address. The IP address is selected - by the network manager based on the location of the computer on the - internet. When the computer is moved to a different part of an - internet, its IP address must be changed. The Ethernet address is - selected by the manufacturer based on the Ethernet address space - licensed by the manufacturer. When the Ethernet hardware interface - board changes, the Ethernet address changes. - -4.2 Typical Translation Scenario - - During normal operation a network application, such as TELNET, sends - an application message to TCP, then TCP sends the corresponding TCP - message to the IP module. The destination IP address is known by the - - - -Socolofsky & Kale [Page 9] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - application, the TCP module, and the IP module. At this point the IP - packet has been constructed and is ready to be given to the Ethernet - driver, but first the destination Ethernet address must be - determined. - - The ARP table is used to look-up the destination Ethernet address. - - 4.3 ARP Request/Response Pair - - But how does the ARP table get filled in the first place? The answer - is that it is filled automatically by ARP on an "as-needed" basis. - - Two things happen when the ARP table can not be used to translate an - address: - - 1. An ARP request packet with a broadcast Ethernet address is sent - out on the network to every computer. - - 2. The outgoing IP packet is queued. - - Every computer's Ethernet interface receives the broadcast Ethernet - frame. Each Ethernet driver examines the Type field in the Ethernet - frame and passes the ARP packet to the ARP module. The ARP request - packet says "If your IP address matches this target IP address, then - please tell me your Ethernet address". An ARP request packet looks - something like this: - - --------------------------------------- - |Sender IP Address 223.1.2.1 | - |Sender Enet Address 08-00-39-00-2F-C3| - --------------------------------------- - |Target IP Address 223.1.2.2 | - |Target Enet Address | - --------------------------------------- - TABLE 2. Example ARP Request - - Each ARP module examines the IP address and if the Target IP address - matches its own IP address, it sends a response directly to the - source Ethernet address. The ARP response packet says "Yes, that - target IP address is mine, let me give you my Ethernet address". An - ARP response packet has the sender/target field contents swapped as - compared to the request. It looks something like this: - - - - - - - - - -Socolofsky & Kale [Page 10] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - --------------------------------------- - |Sender IP Address 223.1.2.2 | - |Sender Enet Address 08-00-28-00-38-A9| - --------------------------------------- - |Target IP Address 223.1.2.1 | - |Target Enet Address 08-00-39-00-2F-C3| - --------------------------------------- - TABLE 3. Example ARP Response - - The response is received by the original sender computer. The - Ethernet driver looks at the Type field in the Ethernet frame then - passes the ARP packet to the ARP module. The ARP module examines the - ARP packet and adds the sender's IP and Ethernet addresses to its ARP - table. - - The updated table now looks like this: - - ---------------------------------- - |IP address Ethernet address | - ---------------------------------- - |223.1.2.1 08-00-39-00-2F-C3| - |223.1.2.2 08-00-28-00-38-A9| - |223.1.2.3 08-00-5A-21-A7-22| - |223.1.2.4 08-00-10-99-AC-54| - ---------------------------------- - TABLE 4. ARP Table after Response - -4.4 Scenario Continued - - The new translation has now been installed automatically in the - table, just milli-seconds after it was needed. As you remember from - step 2 above, the outgoing IP packet was queued. Next, the IP - address to Ethernet address translation is performed by look-up in - the ARP table then the Ethernet frame is transmitted on the Ethernet. - Therefore, with the new steps 3, 4, and 5, the scenario for the - sender computer is: - - 1. An ARP request packet with a broadcast Ethernet address is sent - out on the network to every computer. - - 2. The outgoing IP packet is queued. - - 3. The ARP response arrives with the IP-to-Ethernet address - translation for the ARP table. - - - - - - - -Socolofsky & Kale [Page 11] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - 4. For the queued IP packet, the ARP table is used to translate the - IP address to the Ethernet address. - - 5. The Ethernet frame is transmitted on the Ethernet. - - In summary, when the translation is missing from the ARP table, one - IP packet is queued. The translation data is quickly filled in with - ARP request/response and the queued IP packet is transmitted. - - Each computer has a separate ARP table for each of its Ethernet - interfaces. If the target computer does not exist, there will be no - ARP response and no entry in the ARP table. IP will discard outgoing - IP packets sent to that address. The upper layer protocols can't - tell the difference between a broken Ethernet and the absence of a - computer with the target IP address. - - Some implementations of IP and ARP don't queue the IP packet while - waiting for the ARP response. Instead the IP packet is discarded and - the recovery from the IP packet loss is left to the TCP module or the - UDP network application. This recovery is performed by time-out and - retransmission. The retransmitted message is successfully sent out - onto the network because the first copy of the message has already - caused the ARP table to be filled. - -5. Internet Protocol - - The IP module is central to internet technology and the essence of IP - is its route table. IP uses this in-memory table to make all - decisions about routing an IP packet. The content of the route table - is defined by the network administrator. Mistakes block - communication. - - To understand how a route table is used is to understand - internetworking. This understanding is necessary for the successful - administration and maintenance of an IP network. - - The route table is best understood by first having an overview of - routing, then learning about IP network addresses, and then looking - at the details. - -5.1 Direct Routing - - The figure below is of a tiny internet with 3 computers: A, B, and C. - Each computer has the same TCP/IP protocol stack as in Figure 1. - Each computer's Ethernet interface has its own Ethernet address. - Each computer has an IP address assigned to the IP interface by the - network manager, who also has assigned an IP network number to the - Ethernet. - - - -Socolofsky & Kale [Page 12] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - A B C - | | | - --o------o------o-- - Ethernet 1 - IP network "development" - - Figure 6. One IP Network - - When A sends an IP packet to B, the IP header contains A's IP address - as the source IP address, and the Ethernet header contains A's - Ethernet address as the source Ethernet address. Also, the IP header - contains B's IP address as the destination IP address and the - Ethernet header contains B's Ethernet address as the destination - Ethernet address. - - ---------------------------------------- - |address source destination| - ---------------------------------------- - |IP header A B | - |Ethernet header A B | - ---------------------------------------- - TABLE 5. Addresses in an Ethernet frame for an IP packet - from A to B - - For this simple case, IP is overhead because the IP adds little to - the service offered by Ethernet. However, IP does add cost: the - extra CPU processing and network bandwidth to generate, transmit, and - parse the IP header. - - When B's IP module receives the IP packet from A, it checks the - destination IP address against its own, looking for a match, then it - passes the datagram to the upper-level protocol. - - This communication between A and B uses direct routing. - -5.2 Indirect Routing - - The figure below is a more realistic view of an internet. It is - composed of 3 Ethernets and 3 IP networks connected by an IP-router - called computer D. Each IP network has 4 computers; each computer - has its own IP address and Ethernet address. - - - - - - - - - - -Socolofsky & Kale [Page 13] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - A B C ----D---- E F G - | | | | | | | | | - --o------o------o------o- | -o------o------o------o-- - Ethernet 1 | Ethernet 2 - IP network "development" | IP network "accounting" - | - | - | H I J - | | | | - --o-----o------o------o-- - Ethernet 3 - IP network "factory" - - Figure 7. Three IP Networks; One internet - - Except for computer D, each computer has a TCP/IP protocol stack like - that in Figure 1. Computer D is the IP-router; it is connected to - all 3 networks and therefore has 3 IP addresses and 3 Ethernet - addresses. Computer D has a TCP/IP protocol stack similar to that in - Figure 3, except that it has 3 ARP modules and 3 Ethernet drivers - instead of 2. Please note that computer D has only one IP module. - - The network manager has assigned a unique number, called an IP - network number, to each of the Ethernets. The IP network numbers are - not shown in this diagram, just the network names. - - When computer A sends an IP packet to computer B, the process is - identical to the single network example above. Any communication - between computers located on a single IP network matches the direct - routing example discussed previously. - - When computer D and A communicate, it is direct communication. When - computer D and E communicate, it is direct communication. When - computer D and H communicate, it is direct communication. This is - because each of these pairs of computers is on the same IP network. - - However, when computer A communicates with a computer on the far side - of the IP-router, communication is no longer direct. A must use D to - forward the IP packet to the next IP network. This communication is - called "indirect". - - This routing of IP packets is done by IP modules and happens - transparently to TCP, UDP, and the network applications. - - If A sends an IP packet to E, the source IP address and the source - Ethernet address are A's. The destination IP address is E's, but - because A's IP module sends the IP packet to D for forwarding, the - destination Ethernet address is D's. - - - -Socolofsky & Kale [Page 14] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - ---------------------------------------- - |address source destination| - ---------------------------------------- - |IP header A E | - |Ethernet header A D | - ---------------------------------------- - TABLE 6. Addresses in an Ethernet frame for an IP packet - from A to E (before D) - - D's IP module receives the IP packet and upon examining the - destination IP address, says "This is not my IP address," and sends - the IP packet directly to E. - - ---------------------------------------- - |address source destination| - ---------------------------------------- - |IP header A E | - |Ethernet header D E | - ---------------------------------------- - TABLE 7. Addresses in an Ethernet frame for an IP packet - from A to E (after D) - - In summary, for direct communication, both the source IP address and - the source Ethernet address is the sender's, and the destination IP - address and the destination Ethernet address is the recipient's. For - indirect communication, the IP address and Ethernet addresses do not - pair up in this way. - - This example internet is a very simple one. Real networks are often - complicated by many factors, resulting in multiple IP-routers and - several types of physical networks. This example internet might have - come about because the network manager wanted to split a large - Ethernet in order to localize Ethernet broadcast traffic. - -5.3 IP Module Routing Rules - - This overview of routing has shown what happens, but not how it - happens. Now let's examine the rules, or algorithm, used by the IP - module. - - For an outgoing IP packet, entering IP from an upper layer, IP must - decide whether to send the IP packet directly or indirectly, and IP - must choose a lower network interface. These choices are made by - consulting the route table. - - For an incoming IP packet, entering IP from a lower interface, IP - must decide whether to forward the IP packet or pass it to an upper - layer. If the IP packet is being forwarded, it is treated as an - - - -Socolofsky & Kale [Page 15] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - outgoing IP packet. - - When an incoming IP packet arrives it is never forwarded back out - through the same network interface. - - These decisions are made before the IP packet is handed to the lower - interface and before the ARP table is consulted. - -5.4 IP Address - - The network manager assigns IP addresses to computers according to - the IP network to which the computer is attached. One part of a 4- - byte IP address is the IP network number, the other part is the IP - computer number (or host number). For the computer in table 1, with - an IP address of 223.1.2.1, the network number is 223.1.2 and the - host number is number 1. - - The portion of the address that is used for network number and for - host number is defined by the upper bits in the 4-byte address. All - example IP addresses in this tutorial are of type class C, meaning - that the upper 3 bits indicate that 21 bits are the network number - and 8 bits are the host number. This allows 2,097,152 class C - networks up to 254 hosts on each network. - - The IP address space is administered by the NIC (Network Information - Center). All internets that are connected to the single world-wide - Internet must use network numbers assigned by the NIC. If you are - setting up your own internet and you are not intending to connect it - to the Internet, you should still obtain your network numbers from - the NIC. If you pick your own number, you run the risk of confusion - and chaos in the eventuality that your internet is connected to - another internet. - -5.5 Names - - People refer to computers by names, not numbers. A computer called - alpha might have the IP address of 223.1.2.1. For small networks, - this name-to-address translation data is often kept on each computer - in the "hosts" file. For larger networks, this translation data file - is stored on a server and accessed across the network when needed. A - few lines from that file might look like this: - - 223.1.2.1 alpha - 223.1.2.2 beta - 223.1.2.3 gamma - 223.1.2.4 delta - 223.1.3.2 epsilon - 223.1.4.2 iota - - - -Socolofsky & Kale [Page 16] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - The IP address is the first column and the computer name is the - second column. - - In most cases, you can install identical "hosts" files on all - computers. You may notice that "delta" has only one entry in this - file even though it has 3 IP addresses. Delta can be reached with - any of its IP addresses; it does not matter which one is used. When - delta receives an IP packet and looks at the destination address, it - will recognize any of its own IP addresses. - - IP networks are also given names. If you have 3 IP networks, your - "networks" file for documenting these names might look something like - this: - - 223.1.2 development - 223.1.3 accounting - 223.1.4 factory - - The IP network number is in the first column and its name is in the - second column. - - From this example you can see that alpha is computer number 1 on the - development network, beta is computer number 2 on the development - network and so on. You might also say that alpha is development.1, - Beta is development.2, and so on. - - The above hosts file is adequate for the users, but the network - manager will probably replace the line for delta with: - - 223.1.2.4 devnetrouter delta - 223.1.3.1 facnetrouter - 223.1.4.1 accnetrouter - - These three new lines for the hosts file give each of delta's IP - addresses a meaningful name. In fact, the first IP address listed - has 2 names; "delta" and "devnetrouter" are synonyms. In practice - "delta" is the general-purpose name of the computer and the other 3 - names are only used when administering the IP route table. - - These files are used by network administration commands and network - applications to provide meaningful names. They are not required for - operation of an internet, but they do make it easier for us. - -5.6 IP Route Table - - How does IP know which lower network interface to use when sending - out a IP packet? IP looks it up in the route table using a search - key of the IP network number extracted from the IP destination - - - -Socolofsky & Kale [Page 17] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - address. - - The route table contains one row for each route. The primary columns - in the route table are: IP network number, direct/indirect flag, - router IP address, and interface number. This table is referred to - by IP for each outgoing IP packet. - - On most computers the route table can be modified with the "route" - command. The content of the route table is defined by the network - manager, because the network manager assigns the IP addresses to the - computers. - -5.7 Direct Routing Details - - To explain how it is used, let us visit in detail the routing - situations we have reviewed previously. - - --------- --------- - | alpha | | beta | - | 1 | | 1 | - --------- --------- - | | - --------o---------------o- - Ethernet 1 - IP network "development" - - Figure 8. Close-up View of One IP Network - - The route table inside alpha looks like this: - - -------------------------------------------------------------- - |network direct/indirect flag router interface number| - -------------------------------------------------------------- - |development direct 1 | - -------------------------------------------------------------- - TABLE 8. Example Simple Route Table - - This view can be seen on some UNIX systems with the "netstat -r" - command. With this simple network, all computers have identical - routing tables. - - For discussion, the table is printed again without the network number - translated to its network name. - - - - - - - - -Socolofsky & Kale [Page 18] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - -------------------------------------------------------------- - |network direct/indirect flag router interface number| - -------------------------------------------------------------- - |223.1.2 direct 1 | - -------------------------------------------------------------- - TABLE 9. Example Simple Route Table with Numbers - -5.8 Direct Scenario - - Alpha is sending an IP packet to beta. The IP packet is in alpha's - IP module and the destination IP address is beta or 223.1.2.2. IP - extracts the network portion of this IP address and scans the first - column of the table looking for a match. With this network a match - is found on the first entry. - - The other information in this entry indicates that computers on this - network can be reached directly through interface number 1. An ARP - table translation is done on beta's IP address then the Ethernet - frame is sent directly to beta via interface number 1. - - If an application tries to send data to an IP address that is not on - the development network, IP will be unable to find a match in the - route table. IP then discards the IP packet. Some computers provide - a "Network not reachable" error message. - -5.9 Indirect Routing Details - - Now, let's take a closer look at the more complicated routing - scenario that we examined previously. - - - - - - - - - - - - - - - - - - - - - - -Socolofsky & Kale [Page 19] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - --------- --------- --------- - | alpha | | delta | |epsilon| - | 1 | |1 2 3| | 1 | - --------- --------- --------- - | | | | | - --------o---------------o- | -o----------------o-------- - Ethernet 1 | Ethernet 2 - IP network "Development" | IP network "accounting" - | - | -------- - | | iota | - | | 1 | - | -------- - | | - --o--------o-------- - Ethernet 3 - IP network "factory" - - Figure 9. Close-up View of Three IP Networks - - The route table inside alpha looks like this: - - --------------------------------------------------------------------- - |network direct/indirect flag router interface number| - --------------------------------------------------------------------- - |development direct 1 | - |accounting indirect devnetrouter 1 | - |factory indirect devnetrouter 1 | - --------------------------------------------------------------------- - TABLE 10. Alpha Route Table - - For discussion the table is printed again using numbers instead of - names. - - -------------------------------------------------------------------- - |network direct/indirect flag router interface number| - -------------------------------------------------------------------- - |223.1.2 direct 1 | - |223.1.3 indirect 223.1.2.4 1 | - |223.1.4 indirect 223.1.2.4 1 | - -------------------------------------------------------------------- - TABLE 11. Alpha Route Table with Numbers - - The router in Alpha's route table is the IP address of delta's - connection to the development network. - - - - - - -Socolofsky & Kale [Page 20] - -RFC 1180 A TCP/IP Tutorial January 1991 - - -5.10 Indirect Scenario - - Alpha is sending an IP packet to epsilon. The IP packet is in - alpha's IP module and the destination IP address is epsilon - (223.1.3.2). IP extracts the network portion of this IP address - (223.1.3) and scans the first column of the table looking for a - match. A match is found on the second entry. - - This entry indicates that computers on the 223.1.3 network can be - reached through the IP-router devnetrouter. Alpha's IP module then - does an ARP table translation for devnetrouter's IP address and sends - the IP packet directly to devnetrouter through Alpha's interface - number 1. The IP packet still contains the destination address of - epsilon. - - The IP packet arrives at delta's development network interface and is - passed up to delta's IP module. The destination IP address is - examined and because it does not match any of delta's own IP - addresses, delta decides to forward the IP packet. - - Delta's IP module extracts the network portion of the destination IP - address (223.1.3) and scans its route table for a matching network - field. Delta's route table looks like this: - - ---------------------------------------------------------------------- - |network direct/indirect flag router interface number| - ---------------------------------------------------------------------- - |development direct 1 | - |factory direct 3 | - |accounting direct 2 | - ---------------------------------------------------------------------- - TABLE 12. Delta's Route Table - - Below is delta's table printed again, without the translation to - names. - - ---------------------------------------------------------------------- - |network direct/indirect flag router interface number| - ---------------------------------------------------------------------- - |223.1.2 direct 1 | - |223.1.3 direct 3 | - |223.1.4 direct 2 | - ---------------------------------------------------------------------- - TABLE 13. Delta's Route Table with Numbers - - The match is found on the second entry. IP then sends the IP packet - directly to epsilon through interface number 3. The IP packet - contains the IP destination address of epsilon and the Ethernet - - - -Socolofsky & Kale [Page 21] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - destination address of epsilon. - - The IP packet arrives at epsilon and is passed up to epsilon's IP - module. The destination IP address is examined and found to match - with epsilon's IP address, so the IP packet is passed to the upper - protocol layer. - -5.11 Routing Summary - - When a IP packet travels through a large internet it may go through - many IP-routers before it reaches its destination. The path it takes - is not determined by a central source but is a result of consulting - each of the routing tables used in the journey. Each computer - defines only the next hop in the journey and relies on that computer - to send the IP packet on its way. - -5.12 Managing the Routes - - Maintaining correct routing tables on all computers in a large - internet is a difficult task; network configuration is being modified - constantly by the network managers to meet changing needs. Mistakes - in routing tables can block communication in ways that are - excruciatingly tedious to diagnose. - - Keeping a simple network configuration goes a long way towards making - a reliable internet. For instance, the most straightforward method - of assigning IP networks to Ethernet is to assign a single IP network - number to each Ethernet. - - Help is also available from certain protocols and network - applications. ICMP (Internet Control Message Protocol) can report - some routing problems. For small networks the route table is filled - manually on each computer by the network administrator. For larger - networks the network administrator automates this manual operation - with a routing protocol to distribute routes throughout a network. - - When a computer is moved from one IP network to another, its IP - address must change. When a computer is removed from an IP network - its old address becomes invalid. These changes require frequent - updates to the "hosts" file. This flat file can become difficult to - maintain for even medium-size networks. The Domain Name System helps - solve these problems. - -6. User Datagram Protocol - - UDP is one of the two main protocols to reside on top of IP. It - offers service to the user's network applications. Example network - applications that use UDP are: Network File System (NFS) and Simple - - - -Socolofsky & Kale [Page 22] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - Network Management Protocol (SNMP). The service is little more than - an interface to IP. - - UDP is a connectionless datagram delivery service that does not - guarantee delivery. UDP does not maintain an end-to-end connection - with the remote UDP module; it merely pushes the datagram out on the - net and accepts incoming datagrams off the net. - - UDP adds two values to what is provided by IP. One is the - multiplexing of information between applications based on port - number. The other is a checksum to check the integrity of the data. - -6.1 Ports - - How does a client on one computer reach the server on another? - - The path of communication between an application and UDP is through - UDP ports. These ports are numbered, beginning with zero. An - application that is offering service (the server) waits for messages - to come in on a specific port dedicated to that service. The server - waits patiently for any client to request service. - - For instance, the SNMP server, called an SNMP agent, always waits on - port 161. There can be only one SNMP agent per computer because - there is only one UDP port number 161. This port number is well - known; it is a fixed number, an internet assigned number. If an SNMP - client wants service, it sends its request to port number 161 of UDP - on the destination computer. - - When an application sends data out through UDP it arrives at the far - end as a single unit. For example, if an application does 5 writes - to the UDP port, the application at the far end will do 5 reads from - the UDP port. Also, the size of each write matches the size of each - read. - - UDP preserves the message boundary defined by the application. It - never joins two application messages together, or divides a single - application message into parts. - -6.2 Checksum - - An incoming IP packet with an IP header type field indicating "UDP" - is passed up to the UDP module by IP. When the UDP module receives - the UDP datagram from IP it examines the UDP checksum. If the - checksum is zero, it means that checksum was not calculated by the - sender and can be ignored. Thus the sending computer's UDP module - may or may not generate checksums. If Ethernet is the only network - between the 2 UDP modules communicating, then you may not need - - - -Socolofsky & Kale [Page 23] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - checksumming. However, it is recommended that checksum generation - always be enabled because at some point in the future a route table - change may send the data across less reliable media. - - If the checksum is valid (or zero), the destination port number is - examined and if an application is bound to that port, an application - message is queued for the application to read. Otherwise the UDP - datagram is discarded. If the incoming UDP datagrams arrive faster - than the application can read them and if the queue fills to a - maximum value, UDP datagrams are discarded by UDP. UDP will continue - to discard UDP datagrams until there is space in the queue. - -7. Transmission Control Protocol - - TCP provides a different service than UDP. TCP offers a connection- - oriented byte stream, instead of a connectionless datagram delivery - service. TCP guarantees delivery, whereas UDP does not. - - TCP is used by network applications that require guaranteed delivery - and cannot be bothered with doing time-outs and retransmissions. The - two most typical network applications that use TCP are File Transfer - Protocol (FTP) and the TELNET. Other popular TCP network - applications include X-Window System, rcp (remote copy), and the r- - series commands. TCP's greater capability is not without cost: it - requires more CPU and network bandwidth. The internals of the TCP - module are much more complicated than those in a UDP module. - - Similar to UDP, network applications connect to TCP ports. Well- - defined port numbers are dedicated to specific applications. For - instance, the TELNET server uses port number 23. The TELNET client - can find the server simply by connecting to port 23 of TCP on the - specified computer. - - When the application first starts using TCP, the TCP module on the - client's computer and the TCP module on the server's computer start - communicating with each other. These two end-point TCP modules - contain state information that defines a virtual circuit. This - virtual circuit consumes resources in both TCP end-points. The - virtual circuit is full duplex; data can go in both directions - simultaneously. The application writes data to the TCP port, the - data traverses the network and is read by the application at the far - end. - - TCP packetizes the byte stream at will; it does not retain the - boundaries between writes. For example, if an application does 5 - writes to the TCP port, the application at the far end might do 10 - reads to get all the data. Or it might get all the data with a - single read. There is no correlation between the number and size of - - - -Socolofsky & Kale [Page 24] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - writes at one end to the number and size of reads at the other end. - - TCP is a sliding window protocol with time-out and retransmits. - Outgoing data must be acknowledged by the far-end TCP. - Acknowledgements can be piggybacked on data. Both receiving ends can - flow control the far end, thus preventing a buffer overrun. - - As with all sliding window protocols, the protocol has a window size. - The window size determines the amount of data that can be transmitted - before an acknowledgement is required. For TCP, this amount is not a - number of TCP segments but a number of bytes. - -8. Network Applications - - Why do both TCP and UDP exist, instead of just one or the other? - - They supply different services. Most applications are implemented to - use only one or the other. You, the programmer, choose the protocol - that best meets your needs. If you need a reliable stream delivery - service, TCP might be best. If you need a datagram service, UDP - might be best. If you need efficiency over long-haul circuits, TCP - might be best. If you need efficiency over fast networks with short - latency, UDP might be best. If your needs do not fall nicely into - these categories, then the "best" choice is unclear. However, - applications can make up for deficiencies in the choice. For - instance if you choose UDP and you need reliability, then the - application must provide reliability. If you choose TCP and you need - a record oriented service, then the application must insert markers - in the byte stream to delimit records. - - What network applications are available? - - There are far too many to list. The number is growing continually. - Some of the applications have existed since the beginning of internet - technology: TELNET and FTP. Others are relatively new: X-Windows and - SNMP. The following is a brief description of the applications - mentioned in this tutorial. - -8.1 TELNET - - TELNET provides a remote login capability on TCP. The operation and - appearance is similar to keyboard dialing through a telephone switch. - On the command line the user types "telnet delta" and receives a - login prompt from the computer called "delta". - - TELNET works well; it is an old application and has widespread - interoperability. Implementations of TELNET usually work between - different operating systems. For instance, a TELNET client may be on - - - -Socolofsky & Kale [Page 25] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - VAX/VMS and the server on UNIX System V. - -8.2 FTP - - File Transfer Protocol (FTP), as old as TELNET, also uses TCP and has - widespread interoperability. The operation and appearance is as if - you TELNETed to the remote computer. But instead of typing your - usual commands, you have to make do with a short list of commands for - directory listings and the like. FTP commands allow you to copy - files between computers. - -8.3 rsh - - Remote shell (rsh or remsh) is one of an entire family of remote UNIX - style commands. The UNIX copy command, cp, becomes rcp. The UNIX - "who is logged in" command, who, becomes rwho. The list continues - and is referred to collectively to as the "r" series commands or the - "r*" (r star) commands. - - The r* commands mainly work between UNIX systems and are designed for - interaction between trusted hosts. Little consideration is given to - security, but they provide a convenient user environment. - - To execute the "cc file.c" command on a remote computer called delta, - type "rsh delta cc file.c". To copy the "file.c" file to delta, type - "rcp file.c delta:". To login to delta, type "rlogin delta", and if - you administered the computers in a certain way, you will not be - challenged with a password prompt. - -8.4 NFS - - Network File System, first developed by Sun Microsystems Inc, uses - UDP and is excellent for mounting UNIX file systems on multiple - computers. A diskless workstation can access its server's hard disk - as if the disk were local to the workstation. A single disk copy of - a database on mainframe "alpha" can also be used by mainframe "beta" - if the database's file system is NFS mounted on "beta". - - NFS adds significant load to a network and has poor utility across - slow links, but the benefits are strong. The NFS client is - implemented in the kernel, allowing all applications and commands to - use the NFS mounted disk as if it were local disk. - -8.5 SNMP - - Simple Network Management Protocol (SNMP) uses UDP and is designed - for use by central network management stations. It is a well known - fact that if given enough data, a network manager can detect and - - - -Socolofsky & Kale [Page 26] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - diagnose network problems. The central station uses SNMP to collect - this data from other computers on the network. SNMP defines the - format for the data; it is left to the central station or network - manager to interpret the data. - -8.6 X-Window - - The X Window System uses the X Window protocol on TCP to draw windows - on a workstation's bitmap display. X Window is much more than a - utility for drawing windows; it is entire philosophy for designing a - user interface. - -9. Other Information - - Much information about internet technology was not included in this - tutorial. This section lists information that is considered the next - level of detail for the reader who wishes to learn more. - - o administration commands: arp, route, and netstat - o ARP: permanent entry, publish entry, time-out entry, spoofing - o IP route table: host entry, default gateway, subnets - o IP: time-to-live counter, fragmentation, ICMP - o RIP, routing loops - o Domain Name System - -10. References - - [1] Comer, D., "Internetworking with TCP/IP Principles, Protocols, - and Architecture", Prentice Hall, Englewood Cliffs, New Jersey, - U.S.A., 1988. - - [2] Feinler, E., et al, DDN Protocol Handbook, Volume 2 and 3, DDN - Network Information Center, SRI International, 333 Ravenswood - Avenue, Room EJ291, Menlow Park, California, U.S.A., 1985. - - [3] Spider Systems, Ltd., "Packets and Protocols", Spider Systems - Ltd., Stanwell Street, Edinburgh, U.K. EH6 5NG, 1990. - -11. Relation to other RFCs - - This RFC is a tutorial and it does not UPDATE or OBSOLETE any other - RFC. - -12. Security Considerations - - There are security considerations within the TCP/IP protocol suite. - To some people these considerations are serious problems, to others - they are not; it depends on the user requirements. - - - -Socolofsky & Kale [Page 27] - -RFC 1180 A TCP/IP Tutorial January 1991 - - - This tutorial does not discuss these issues, but if you want to learn - more you should start with the topic of ARP-spoofing, then use the - "Security Considerations" section of RFC 1122 to lead you to more - information. - -13. Authors' Addresses - - Theodore John Socolofsky - Spider Systems Limited - Spider Park - Stanwell Street - Edinburgh EH6 5NG - United Kingdom - - Phone: - from UK 031-554-9424 - from USA 011-44-31-554-9424 - Fax: - from UK 031-554-0649 - from USA 011-44-31-554-0649 - - EMail: TEDS@SPIDER.CO.UK - - - Claudia Jeanne Kale - 12 Gosford Place - Edinburgh EH6 4BJ - United Kingdom - - Phone: - from UK 031-554-7432 - from USA 011-44-31-554-7432 - - EMail: CLAUDIAK@SPIDER.CO.UK - - - - - - - - - - - - - - - - - -Socolofsky & Kale [Page 28] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1185.txt b/ext/picotcp/RFC/rfc1185.txt deleted file mode 100644 index 4f467f5..0000000 --- a/ext/picotcp/RFC/rfc1185.txt +++ /dev/null @@ -1,1179 +0,0 @@ - - - - - - -Network Working Group V. Jacobson -Request for Comments: 1185 LBL - R. Braden - ISI - L. Zhang - PARC - October 1990 - - - TCP Extension for High-Speed Paths - -Status of This Memo - - This memo describes an Experimental Protocol extension to TCP for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "IAB - Official Protocol Standards" for the standardization state and status - of this protocol. Distribution of this memo is unlimited. - -Summary - - This memo describes a small extension to TCP to support reliable - operation over very high-speed paths, using sender timestamps - transmitted using the TCP Echo option proposed in RFC-1072. - -1. INTRODUCTION - - TCP uses positive acknowledgments and retransmissions to provide - reliable end-to-end delivery over a full-duplex virtual circuit - called a connection [Postel81]. A connection is defined by its two - end points; each end point is a "socket", i.e., a (host,port) pair. - To protect against data corruption, TCP uses an end-to-end checksum. - Duplication and reordering are handled using a fine-grained sequence - number space, with each octet receiving a distinct sequence number. - - The TCP protocol [Postel81] was designed to operate reliably over - almost any transmission medium regardless of transmission rate, - delay, corruption, duplication, or reordering of segments. In - practice, proper TCP implementations have demonstrated remarkable - robustness in adapting to a wide range of network characteristics. - For example, TCP implementations currently adapt to transfer rates in - the range of 100 bps to 10**7 bps and round-trip delays in the range - 1 ms to 100 seconds. - - However, the introduction of fiber optics is resulting in ever-higher - transmission speeds, and the fastest paths are moving out of the - domain for which TCP was originally engineered. This memo and RFC- - 1072 [Jacobson88] propose modest extensions to TCP to extend the - - - -Jacobson, Braden & Zhang [Page 1] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - domain of its application to higher speeds. - - There is no one-line answer to the question: "How fast can TCP go?". - The issues are reliability and performance, and these depend upon the - round-trip delay and the maximum time that segments may be queued in - the Internet, as well as upon the transmission speed. We must think - through these relationships very carefully if we are to successfully - extend TCP's domain. - - TCP performance depends not upon the transfer rate itself, but rather - upon the product of the transfer rate and the round-trip delay. This - "bandwidth*delay product" measures the amount of data that would - "fill the pipe"; it is the buffer space required at sender and - receiver to obtain maximum throughput on the TCP connection over the - path. RFC-1072 proposed a set of TCP extensions to improve TCP - efficiency for "LFNs" (long fat networks), i.e., networks with large - bandwidth*delay products. - - On the other hand, high transfer rate can threaten TCP reliability by - violating the assumptions behind the TCP mechanism for duplicate - detection and sequencing. The present memo specifies a solution for - this problem, extending TCP reliability to transfer rates well beyond - the foreseeable upper limit of bandwidth. - - An especially serious kind of error may result from an accidental - reuse of TCP sequence numbers in data segments. Suppose that an "old - duplicate segment", e.g., a duplicate data segment that was delayed - in Internet queues, was delivered to the receiver at the wrong moment - so that its sequence numbers fell somewhere within the current - window. There would be no checksum failure to warn of the error, and - the result could be an undetected corruption of the data. Reception - of an old duplicate ACK segment at the transmitter could be only - slightly less serious: it is likely to lock up the connection so that - no further progress can be made and a RST is required to - resynchronize the two ends. - - Duplication of sequence numbers might happen in either of two ways: - - (1) Sequence number wrap-around on the current connection - - A TCP sequence number contains 32 bits. At a high enough - transfer rate, the 32-bit sequence space may be "wrapped" - (cycled) within the time that a segment may be delayed in - queues. Section 2 discusses this case and proposes a mechanism - to reject old duplicates on the current connection. - - (2) Segment from an earlier connection incarnation - - - - -Jacobson, Braden & Zhang [Page 2] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - Suppose a connection terminates, either by a proper close - sequence or due to a host crash, and the same connection (i.e., - using the same pair of sockets) is immediately reopened. A - delayed segment from the terminated connection could fall within - the current window for the new incarnation and be accepted as - valid. This case is discussed in Section 3. - - TCP reliability depends upon the existence of a bound on the lifetime - of a segment: the "Maximum Segment Lifetime" or MSL. An MSL is - generally required by any reliable transport protocol, since every - sequence number field must be finite, and therefore any sequence - number may eventually be reused. In the Internet protocol suite, the - MSL bound is enforced by an IP-layer mechanism, the "Time-to-Live" or - TTL field. - - Watson's Delta-T protocol [Watson81] includes network-layer - mechanisms for precise enforcement of an MSL. In contrast, the IP - mechanism for MSL enforcement is loosely defined and even more - loosely implemented in the Internet. Therefore, it is unwise to - depend upon active enforcement of MSL for TCP connections, and it is - unrealistic to imagine setting MSL's smaller than the current values - (e.g., 120 seconds specified for TCP). The timestamp algorithm - described in the following section gives a way out of this dilemma - for high-speed networks. - - -2. SEQUENCE NUMBER WRAP-AROUND - - 2.1 Background - - Avoiding reuse of sequence numbers within the same connection is - simple in principle: enforce a segment lifetime shorter than the - time it takes to cycle the sequence space, whose size is - effectively 2**31. - - More specifically, if the maximum effective bandwidth at which TCP - is able to transmit over a particular path is B bytes per second, - then the following constraint must be satisfied for error-free - operation: - - 2**31 / B > MSL (secs) [1] - - The following table shows the value for Twrap = 2**31/B in - seconds, for some important values of the bandwidth B: - - - - - - - -Jacobson, Braden & Zhang [Page 3] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - Network B*8 B Twrap - bits/sec bytes/sec secs - _______ _______ ______ ______ - - ARPANET 56kbps 7KBps 3*10**5 (~3.6 days) - - DS1 1.5Mbps 190KBps 10**4 (~3 hours) - - Ethernet 10Mbps 1.25MBps 1700 (~30 mins) - - DS3 45Mbps 5.6MBps 380 - - FDDI 100Mbps 12.5MBps 170 - - Gigabit 1Gbps 125MBps 17 - - - It is clear why wrap-around of the sequence space was not a - problem for 56kbps packet switching or even 10Mbps Ethernets. On - the other hand, at DS3 and FDDI speeds, Twrap is comparable to the - 2 minute MSL assumed by the TCP specification [Postel81]. Moving - towards gigabit speeds, Twrap becomes too small for reliable - enforcement by the Internet TTL mechanism. - - The 16-bit window field of TCP limits the effective bandwidth B to - 2**16/RTT, where RTT is the round-trip time in seconds - [McKenzie89]. If the RTT is large enough, this limits B to a - value that meets the constraint [1] for a large MSL value. For - example, consider a transcontinental backbone with an RTT of 60ms - (set by the laws of physics). With the bandwidth*delay product - limited to 64KB by the TCP window size, B is then limited to - 1.1MBps, no matter how high the theoretical transfer rate of the - path. This corresponds to cycling the sequence number space in - Twrap= 2000 secs, which is safe in today's Internet. - - Based on this reasoning, an earlier RFC [McKenzie89] has cautioned - that expanding the TCP window space as proposed in RFC-1072 will - lead to sequence wrap-around and hence to possible data - corruption. We believe that this is mis-identifying the culprit, - which is not the larger window but rather the high bandwidth. - - For example, consider a (very large) FDDI LAN with a diameter - of 10km. Using the speed of light, we can compute the RTT - across the ring as (2*10**4)/(3*10**8) = 67 microseconds, and - the delay*bandwidth product is then 833 bytes. A TCP - connection across this LAN using a window of only 833 bytes - will run at the full 100mbps and can wrap the sequence space - in about 3 minutes, very close to the MSL of TCP. Thus, high - - - -Jacobson, Braden & Zhang [Page 4] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - speed alone can cause a reliability problem with sequence - number wrap-around, even without extended windows. - - An "obvious" fix for the problem of cycling the sequence space is - to increase the size of the TCP sequence number field. For - example, the sequence number field (and also the acknowledgment - field) could be expanded to 64 bits. However, the proposals for - making such a change while maintaining compatibility with current - TCP have tended towards complexity and ugliness. - - This memo proposes a simple solution to the problem, using the TCP - echo options defined in RFC-1072. Section 2.2 which follows - describes the original use of these options to carry timestamps in - order to measure RTT accurately. Section 2.3 proposes a method of - using these same timestamps to reject old duplicate segments that - could corrupt an open TCP connection. Section 3 discusses the - application of this mechanism to avoiding old duplicates from - previous incarnations. - - 2.2 TCP Timestamps - - RFC-1072 defined two TCP options, Echo and Echo Reply. Echo - carries a 32-bit number, and the receiver of the option must - return this same value to the source host in an Echo Reply option. - - RFC-1072 furthermore describes the use of these options to contain - 32-bit timestamps, for measuring the RTT. A TCP sending data - would include Echo options containing the current clock value. - The receiver would echo these timestamps in returning segments - (generally, ACK segments). The difference between a timestamp - from an Echo Reply option and the current time would then measure - the RTT at the sender. - - This mechanism was designed to solve the following problem: almost - all TCP implementations base their RTT measurements on a sample of - only one packet per window. If we look at RTT estimation as a - signal processing problem (which it is), a data signal at some - frequency (the packet rate) is being sampled at a lower frequency - (the window rate). Unfortunately, this lower sampling frequency - violates Nyquist's criteria and may introduce "aliasing" artifacts - into the estimated RTT [Hamming77]. - - A good RTT estimator with a conservative retransmission timeout - calculation can tolerate the aliasing when the sampling frequency - is "close" to the data frequency. For example, with a window of - 8 packets, the sample rate is 1/8 the data frequency -- less than - an order of magnitude different. However, when the window is tens - or hundreds of packets, the RTT estimator may be seriously in - - - -Jacobson, Braden & Zhang [Page 5] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - error, resulting in spurious retransmissions. - - A solution to the aliasing problem that actually simplifies the - sender substantially (since the RTT code is typically the single - biggest protocol cost for TCP) is as follows: the will sender - place a timestamp in each segment and the receiver will reflect - these timestamps back in ACK segments. Then a single subtract - gives the sender an accurate RTT measurement for every ACK segment - (which will correspond to every other data segment, with a - sensible receiver). RFC-1072 defined a timestamp echo option for - this purpose. - - It is vitally important to use the timestamp echo option with big - windows; otherwise, the door is opened to some dangerous - instabilities due to aliasing. Furthermore, the option is - probably useful for all TCP's, since it simplifies the sender. - - 2.3 Avoiding Old Duplicate Segments - - Timestamps carried from sender to receiver in TCP Echo options can - also be used to prevent data corruption caused by sequence number - wrap-around, as this section describes. - - 2.3.1 Basic Algorithm - - Assume that every received TCP segment contains a timestamp. - The basic idea is that a segment received with a timestamp that - is earlier than the timestamp of the most recently accepted - segment can be discarded as an old duplicate. More - specifically, the following processing is to be performed on - normal incoming segments: - - R1) If the timestamp in the arriving segment timestamp is less - than the timestamp of the most recently received in- - sequence segment, treat the arriving segment as not - acceptable: - - If SEG.LEN > 0, send an acknowledgement in reply as - specified in RFC-793 page 69, and drop the segment; - otherwise, just silently drop the segment.* - -_________________________ -*Sending an ACK segment in reply is not strictly necessary, since the -case can only arise when a later in-order segment has already been -received. However, for consistency and simplicity, we suggest -treating a timestamp failure the same way TCP treats any other -unacceptable segment. - - - - -Jacobson, Braden & Zhang [Page 6] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - R2) If the segment is outside the window, reject it (normal - TCP processing) - - R3) If an arriving segment is in-sequence (i.e, at the left - window edge), accept it normally and record its timestamp. - - R4) Otherwise, treat the segment as a normal in-window, out- - of-sequence TCP segment (e.g., queue it for later delivery - to the user). - - - Steps R2-R4 are the normal TCP processing steps specified by - RFC-793, except that in R3 the latest timestamp is set from - each in-sequence segment that is accepted. Thus, the latest - timestamp recorded at the receiver corresponds to the left edge - of the window and only advances when the left edge moves - [Jacobson88]. - - It is important to note that the timestamp is checked only when - a segment first arrives at the receiver, regardless of whether - it is in-sequence or is queued. Consider the following - example. - - Suppose the segment sequence: A.1, B.1, C.1, ..., Z.1 has - been sent, where the letter indicates the sequence number - and the digit represents the timestamp. Suppose also that - segment B.1 has been lost. The highest in-sequence - timestamp is 1 (from A.1), so C.1, ..., Z.1 are considered - acceptable and are queued. When B is retransmitted as - segment B.2 (using the latest timestamp), it fills the - hole and causes all the segments through Z to be - acknowledged and passed to the user. The timestamps of - the queued segments are *not* inspected again at this - time, since they have already been accepted. When B.2 is - accepted, the receivers's current timestamp is set to 2. - - This rule is vital to allow reasonable performance under loss. - A full window of data is in transit at all times, and after a - loss a full window less one packet will show up out-of-sequence - to be queued at the receiver (e.g., up to ~2**30 bytes of - data); the timestamp option must not result in discarding this - data. - - In certain unlikely circumstances, the algorithm of rules R1-R4 - could lead to discarding some segments unnecessarily, as shown - in the following example: - - Suppose again that segments: A.1, B.1, C.1, ..., Z.1 have - - - -Jacobson, Braden & Zhang [Page 7] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - been sent in sequence and that segment B.1 has been lost. - Furthermore, suppose delivery of some of C.1, ... Z.1 is - delayed until AFTER the retransmission B.2 arrives at the - receiver. These delayed segments will be discarded - unnecessarily when they do arrive, since their timestamps - are now out of date. - - This case is very unlikely to occur. If the retransmission was - triggered by a timeout, some of the segments C.1, ... Z.1 must - have been delayed longer than the RTO time. This is presumably - an unlikely event, or there would be many spurious timeouts and - retransmissions. If B's retransmission was triggered by the - "fast retransmit" algorithm, i.e., by duplicate ACK's, then the - queued segments that caused these ACK's must have been received - already. - - Even if a segment was delayed past the RTO, the selective - acknowledgment (SACK) facility of RFC-1072 will cause the - delayed packets to be retransmitted at the same time as B.2, - avoiding an extra RTT and therefore causing a very small - performance penalty. - - We know of no case with a significant probability of occurrence - in which timestamps will cause performance degradation by - unnecessarily discarding segments. - - 2.3.2 Header Prediction - - "Header prediction" [Jacobson90] is a high-performance - transport protocol implementation technique that is is most - important for high-speed links. This technique optimizes the - code for the most common case: receiving a segment correctly - and in order. Using header prediction, the receiver asks the - question, "Is this segment the next in sequence?" This - question can be answered in fewer machine instructions than the - question, "Is this segment within the window?" - - Adding header prediction to our timestamp procedure leads to - the following sequence for processing an arriving TCP segment: - - H1) Check timestamp (same as step R1 above) - - H2) Do header prediction: if segment is next in sequence and - if there are no special conditions requiring additional - processing, accept the segment, record its timestamp, and - skip H3. - - H3) Process the segment normally, as specified in RFC-793. - - - -Jacobson, Braden & Zhang [Page 8] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - This includes dropping segments that are outside the - window and possibly sending acknowledgments, and queueing - in-window, out-of-sequence segments. - - However, the timestamp check in step H1 is very unlikely to - fail, and it is a relatively expensive operation since it - requires interval arithmetic on a finite field. To perform - this check on every single segment seems like poor - implementation engineering, defeating the purpose of header - prediction. Therefore, we suggest that an implementor - interchange H1 and H2, i.e., perform header prediction FIRST, - performing H1 and H3 only if header prediction fails. We - believe that this change might gain 5-10% in performance on - high-speed networks. - - This reordering does raise a theoretical hazard: a segment from - 2**32 bytes in the past may arrive at exactly the wrong time - and be accepted mistakenly by the header-prediction step. We - make the following argument to show that the probability of - this failure is negligible. - - If all segments are equally likely to show up as old - duplicates, then the probability of an old duplicate - exactly matching the left window edge is the maximum - segment size (MSS) divided by the size of the sequence - space. This ratio must be less than 2**-16, since MSS - must be < 2**16; for example, it will be (2**12)/(2**32) = - 2**-20 for an FDDI link. However, the older a segment is, - the less likely it is to be retained in the Internet, and - under any reasonable model of segment lifetime the - probability of an old duplicate exactly at the left window - edge must be much smaller than 2**16. - - The 16 bit TCP checksum also allows a basic unreliability - of one part in 2**16. A protocol mechanism whose - reliability exceeds the reliability of the TCP checksum - should be considered "good enough", i.e., it won't - contribute significantly to the overall error rate. We - therefore believe we can ignore the problem of an old - duplicate being accepted by doing header prediction before - checking the timestamp. - - 2.3.3 Timestamp Frequency - - It is important to understand that the receiver algorithm for - timestamps does not involve clock synchronization with the - sender. The sender's clock is used to stamp the segments, and - the sender uses this fact to measure RTT's. However, the - - - -Jacobson, Braden & Zhang [Page 9] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - receiver treats the timestamp as simply a monotone-increasing - serial number, without any necessary connection to its clock. - From the receiver's viewpoint, the timestamp is acting as a - logical extension of the high-order bits of the sequence - number. - - However, the receiver algorithm dpes place some requirements on - the frequency of the timestamp "clock": - - (a) Timestamp clock must not be "too slow". - - It must tick at least once for each 2**31 bytes sent. In - fact, in order to be useful to the sender for round trip - timing, the clock should tick at least once per window's - worth of data, and even with the RFC-1072 window - extension, 2**31 bytes must be at least two windows. - - To make this more quantitative, any clock faster than 1 - tick/sec will reject old duplicate segments for link - speeds of ~2 Gbps; a 1ms clock will work up to link - speeds of 2 Tbps (10**12 bps!). - - (b) Timestamp clock must not be "too fast". - - Its cycling time must be greater than MSL seconds. Since - the clock (timestamp) is 32 bits and the worst-case MSL is - 255 seconds, the maximum acceptable clock frequency is one - tick every 59 ns. - - However, since the sender is using the timestamp for RTT - calculations, the timestamp doesn't need to have much more - resolution than the granularity of the retransmit timer, - e.g., tens or hundreds of milliseconds. - - Thus, both limits are easily satisfied with a reasonable clock - rate in the range 1-100ms per tick. - - Using the timestamp option relaxes the requirements on MSL for - avoiding sequence number wrap-around. For example, with a 1 ms - timestamp clock, the 32-bit timestamp will wrap its sign bit in - 25 days. Thus, it will reject old duplicates on the same - connection as long as MSL is 25 days or less. This appears to - be a very safe figure. If the timestamp has 10 ms resolution, - the MSL requirement is boosted to 250 days. An MSL of 25 days - or longer can probably be assumed by the gateway system without - requiring precise MSL enforcement by the TTL value in the IP - layer. - - - - -Jacobson, Braden & Zhang [Page 10] - -RFC 1185 TCP over High-Speed Paths October 1990 - - -3. DUPLICATES FROM EARLIER INCARNATIONS OF CONNECTION - - We turn now to the second potential cause of old duplicate packet - errors: packets from an earlier incarnation of the same connection. - The appendix contains a review the mechanisms currently included in - TCP to handle this problem. These mechanisms depend upon the - enforcement of a maximum segment lifetime (MSL) by the Internet - layer. - - The MSL required to prevent failures due to an earlier connection - incarnation does not depend (directly) upon the transfer rate. - However, the timestamp option used as described in Section 2 can - provide additional security against old duplicates from earlier - connections. Furthermore, we will see that with the universal use of - the timestamp option, enforcement of a maximum segment lifetime would - no longer be required for reliable TCP operation. - - There are two cases to be considered (see the appendix for more - explanation): (1) a system crashing (and losing connection state) - and restarting, and (2) the same connection being closed and reopened - without a loss of host state. These will be described in the - following two sections. - - 3.1 System Crash with Loss of State - - TCP's quiet time of one MSL upon system startup handles the loss - of connection state in a system crash/restart. For an - explanation, see for example "When to Keep Quiet" in the TCP - protocol specification [Postel81]. The MSL that is required here - does not depend upon the transfer speed. The current TCP MSL of 2 - minutes seems acceptable as an operational compromise, as many - host systems take this long to boot after a crash. - - However, the timestamp option may be used to ease the MSL - requirements (or to provide additional security against data - corruption). If timestamps are being used and if the timestamp - clock can be guaranteed to be monotonic over a system - crash/restart, i.e., if the first value of the sender's timestamp - clock after a crash/restart can be guaranteed to be greater than - the last value before the restart, then a quiet time will be - unnecessary. - - To dispense totally with the quiet time would seem to require that - the host clock be synchronized to a time source that is stable - over the crash/restart period, with an accuracy of one timestamp - clock tick or better. Fortunately, we can back off from this - strict requirement. Suppose that the clock is always re- - synchronized to within N timestamp clock ticks and that booting - - - -Jacobson, Braden & Zhang [Page 11] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - (extended with a quiet time, if necessary) takes more than N - ticks. This will guarantee monotonicity of the timestamps, which - can then be used to reject old duplicates even without an enforced - MSL. - - 3.2 Closing and Reopening a Connection - - When a TCP connection is closed, a delay of 2*MSL in TIME-WAIT - state ties up the socket pair for 4 minutes (see Section 3.5 of - [Postel81]. Applications built upon TCP that close one connection - and open a new one (e.g., an FTP data transfer connection using - Stream mode) must choose a new socket pair each time. This delay - serves two different purposes: - - (a) Implement the full-duplex reliable close handshake of TCP. - - The proper time to delay the final close step is not really - related to the MSL; it depends instead upon the RTO for the - FIN segments and therefore upon the RTT of the path.* - Although there is no formal upper-bound on RTT, common - network engineering practice makes an RTT greater than 1 - minute very unlikely. Thus, the 4 minute delay in TIME-WAIT - state works satisfactorily to provide a reliable full-duplex - TCP close. Note again that this is independent of MSL - enforcement and network speed. - - The TIME-WAIT state could cause an indirect performance - problem if an application needed to repeatedly close one - connection and open another at a very high frequency, since - the number of available TCP ports on a host is less than - 2**16. However, high network speeds are not the major - contributor to this problem; the RTT is the limiting factor - in how quickly connections can be opened and closed. - Therefore, this problem will no worse at high transfer - speeds. - - (b) Allow old duplicate segements to expire. - - Suppose that a host keeps a cache of the last timestamp - received from each remote host. This can be used to reject - old duplicate segments from earlier incarnations of the -_________________________ -*Note: It could be argued that the side that is sending a FIN knows -what degree of reliability it needs, and therefore it should be able -to determine the length of the TIME-WAIT delay for the FIN's -recipient. This could be accomplished with an appropriate TCP option -in FIN segments. - - - - -Jacobson, Braden & Zhang [Page 12] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - connection, if the timestamp clock can be guaranteed to have - ticked at least once since the old conennection was open. - This requires that the TIME-WAIT delay plus the RTT together - must be at least one tick of the sender's timestamp clock. - - Note that this is a variant on the mechanism proposed by - Garlick, Rom, and Postel (see the appendix), which required - each host to maintain connection records containing the - highest sequence numbers on every connection. Using - timestamps instead, it is only necessary to keep one quantity - per remote host, regardless of the number of simultaneous - connections to that host. - - We conclude that if all hosts used the TCP timestamp algorithm - described in Section 2, enforcement of a maximum segment lifetime - would be unnecessary and the quiet time at system startup could be - shortened or removed. In any case, the timestamp mechanism can - provide additional security against old duplicates from earlier - connection incarnations. However, a 4 minute TIME-WAIT delay - (unrelated to MSL enforcement or network speed) must be retained - to provide the reliable close handshake of TCP. - -4. CONCLUSIONS - - We have presented a mechanism, based upon the TCP timestamp echo - option of RFC-1072, that will allow very high TCP transfer rates - without reliability problems due to old duplicate segments on the - same connection. This mechanism also provides additional security - against intrusion of old duplicates from earlier incarnations of the - same connection. If the timestamp mechanism were used by all hosts, - the quiet time at system startup could be eliminated and enforcement - of a maximum segment lifetime (MSL) would no longer be necessary. - -REFERENCES - - [Cerf76] Cerf, V., "TCP Resynchronization", Tech Note #79, Digital - Systems Lab, Stanford, January 1976. - - [Dalal74] Dalal, Y., "More on Selecting Sequence Numbers", INWG - Protocol Note #4, October 1974. - - [Garlick77] Garlick, L., R. Rom, and J. Postel, "Issues in Reliable - Host-to-Host Protocols", Proc. Second Berkeley Workshop on - Distributed Data Management and Computer Networks, May 1977. - - [Hamming77] Hamming, R., "Digital Filters", ISBN 0-13-212571-4, - Prentice Hall, Englewood Cliffs, N.J., 1977. - - - - -Jacobson, Braden & Zhang [Page 13] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - [Jacobson88] Jacobson, V., and R. Braden, "TCP Extensions for - Long-Delay Paths", RFC 1072, LBL and USC/Information Sciences - Institute, October 1988. - - [Jacobson90] Jacobson, V., "4BSD Header Prediction", ACM Computer - Communication Review, April 1990. - - [McKenzie89] McKenzie, A., "A Problem with the TCP Big Window - Option", RFC 1110, BBN STC, August 1989. - - [Postel81] Postel, J., "Transmission Control Protocol", RFC 793, - DARPA, September 1981. - - [Tomlinson74] Tomlinson, R., "Selecting Sequence Numbers", INWG - Protocol Note #2, September 1974. - - [Watson81] Watson, R., "Timer-based Mechanisms in Reliable - Transport Protocol Connection Management", Computer Networks, - Vol. 5, 1981. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Jacobson, Braden & Zhang [Page 14] - -RFC 1185 TCP over High-Speed Paths October 1990 - - -APPENDIX -- Protection against Old Duplicates in TCP - - During the development of TCP, a great deal of effort was devoted to - the problem of protecting a TCP connection from segments left from - earlier incarnations of the same connection. Several different - mechanisms were proposed for this purpose [Tomlinson74] [Dalal74] - [Cerf76] [Garlick77]. - - The connection parameters that are required in this discussion are: - - Tc = Connection duration in seconds. - - Nc = Total number of bytes sent on connection. - - B = Effective bandwidth of connection = Nc/Tc. - - Tomlinson proposed a scheme with two parts: a clock-driven selection - of ISN (Initial Sequence Number) for a connection, and a - resynchronization procedure [Tomlinson74]. The clock-driven scheme - chooses: - - ISN = (integer(R*t)) mod 2**32 [2] - - where t is the current time relative to an arbitrary origin, and R is - a constant. R was intended to be chosen so that ISN will advance - faster than sequence numbers will be used up on the connection. - However, at high speeds this will not be true; the consequences of - this will be discussed below. - - The clock-driven choice of ISN in formula [2] guarantees freedom from - old duplicates matching a reopened connection if the original - connection was "short-lived" and "slow". By "short-lived", we mean a - connection that stayed open for a time Tc less than the time to cycle - the ISN, i.e., Tc < 2**32/R seconds. By "slow", we mean that the - effective transfer rate B is less than R. - - This is illustrated in Figure 1, where sequence numbers are plotted - against time. The asterisks show the ISN lines from formula [2], - while the circles represent the trajectories of several short-lived - incarnations of the same connection, each terminating at the "x". - - Note: allowing rapid reuse of connections was believed to be an - important goal during the early TCP development. This - requirement was driven by the hope that TCP would serve as a - basis for user-level transaction protocols as well as - connection-oriented protocols. The paradigm discussed was the - "Christmas Tree" or "Kamikazee" segment that contained SYN and - FIN bits as well as data. Enthusiasm for this was somewhat - - - -Jacobson, Braden & Zhang [Page 15] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - dampened when it was observed that the 3-way SYN handshake and - the FIN handshake mean that 5 packets are required for a minimum - exchange. Furthermore, the TIME-WAIT state delay implies that - the same connection really cannot be reopened immediately. No - further work has been done in this area, although existing - applications (especially SMTP) often generate very short TCP - sessions. The reuse problem is generally avoided by using a - different port pair for each connection. - - - |- 2**32 ISN ISN - | * * - | * * - | * * - | *x * - | o * - ^ | * * - | | * x * - | * o * - S | *o * - e | o * - q | * * - | * * - # | * x * - | *o * - |o_______________*____________ - ^ Time --> - 4.55hrs - - - Figure 1. Clock-Driven ISN avoiding duplication on - short-Lived, slow connections. - - - However, clock-driven ISN selection does not protect against old - duplicate packets for a long-lived or fast connection: the - connection may close (or crash) just as the ISN has cycled around and - reached the same value again. If the connection is then reopened, a - datagram still in transit from the old connection may fall into the - current window. This is illustrated by Figure 2 for a slow, long- - lived connection, and by Figures 3 and 4 for fast connections. In - each case, the point "x" marks the place at which the original - connection closes or crashes. The arrow in Figure 2 illustrates an - old duplicate segment. Figure 3 shows a connection whose total byte - count Nc < 2**32, while Figure 4 concerns Nc >= 2**32. - - To prevent the duplication illustrated in Figure 2, Tomlinson - proposed to "resynchronize" the connection sequence numbers if they - - - -Jacobson, Braden & Zhang [Page 16] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - came within an MSL of the ISN. Resynchronization might take the form - of a delay (point "y") or the choice of a new sequence number (point - "z"). - - |- 2**32 ISN ISN - | * * - | * * - | * * - | * * - | * * - ^ | * * - | | * * - | * * - S | * * - e | * x* y - q | * o * - | * o *z - # | *o * - | * * - |*_________________*____________ - ^ Time --> - 4.55hrs - - Figure 2. Resynchronization to Avoid Duplication - on Slow, Long-Lived Connection - - - - |- 2**32 ISN ISN - | * * - | x o * * - | * * - | o-->o* * - | * * - ^ | o o * - | | * * - | o * * - S | * * - e | o * * - q | * * - | o* * - # | * * - | o * - |*_________________*____________ - ^ Time --> - 4.55hrs - - Figure 3. Duplication on Fast Connection: Nc < 2**32 bytes - - - -Jacobson, Braden & Zhang [Page 17] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - |- 2**32 ISN ISN - | o * * - | x * * - | * * - | o * * - | o * - ^ | * * - | | o * * - | * o * - S | * * - e | o * * - q | * o * - | * * - # | o * - | * o * - |*_________________*____________ - ^ Time --> - 4.55hrs - - Figure 4. Duplication on Fast Connection: Nc > 2**32 bytes - - In summary, Figures 1-4 illustrated four possible failure modes for - old duplicate packets from an earlier incarnation. We will call - these four modes F1 , F2, F3, and F4: - - - F1: B < R, Tc < 4.55 hrs. (Figure 1) - - F2: B < R, Tc >= 4.55 hrs. (Figure 2) - - F3: B >= R, Nc < 2**32 (Figure 3) - - F4: B >= R, Nc >= 2**32 (Figure 4) - - - Another limitation of clock-driven ISN selection should be mentioned. - Tomlinson assumed that the current time t in formula [2] is obtained - from a clock that is persistent over a system crash. For his scheme - to work correctly, the clock must be restarted with an accuracy of - 1/R seconds (e.g, 4 microseconds in the case of TCP). While this may - be possible for some hosts and some crashes, in most cases there will - be an uncertainty in the clock after a crash that ranges from a - second to several minutes. - - As a result of this random clock offset after system - reinitialization, there is a possibility that old segments sent - before the crash may fall into the window of a new connection - incarnation. The solution to this problem that was adopted in the - - - -Jacobson, Braden & Zhang [Page 18] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - final TCP spec is a "quiet time" of MSL seconds when the system is - initialized [Postel81, p. 28]. No TCP connection can be opened until - the expiration of this quiet time. - - A different approach was suggested by Garlick, Rom, and Postel - [Garlick77]. Rather than using clock-driven ISN selection, they - proposed to maintain connection records containing the last ISN used - on every connection. To immediately open a new incarnation of a - connection, the ISN is taken to be greater than the last sequence - number of the previous incarnation, so that the new incarnation will - have unique sequence numbers. To handle a system crash, they - proposed a quiet time, i.e., a delay at system startup time to allow - old duplicates to expire. Note that the connection records need be - kept only for MSL seconds; after that, no collision is possible, and - a new connection can start with sequence number zero. - - The scheme finally adopted for TCP combines features of both these - proposals. TCP uses three mechanisms: - - (A) ISN selection is clock-driven to handle short-lived connections. - The parameter R = 250KBps, so that the ISN value cycles in - 2**32/R = 4.55 hours. - - (B) (One end of) a closed connection is left in a "busy" state, - known as "TIME-WAIT" state, for a time of 2*MSL. TIME-WAIT - state handles the proper close of a long-lived connection - without resynchronization. It also allows reliable completion - of the full-duplex close handshake. - - (C) There is a quiet time of one MSL at system startup. This - handles a crash of a long-lived connection and avoids time - resynchronization problems in (A). - - Notice that (B) and (C) together are logically sufficient to prevent - accidental reuse of sequence numbers from a different incarnation, - for any of the failure modes F1-F4. (A) is not logically necessary - since the close delay (B) makes it impossible to reopen the same TCP - connection immediately. However, the use of (A) does give additional - assurance in a common case, perhaps compensating for a host that has - set its TIME-WAIT state delay too short. - - Some TCP implementations have permitted a connection in the TIME-WAIT - state to be reopened immediately by the other side, thus short- - circuiting mechanism (B). Specifically, a new SYN for the same - socket pair is accepted when the earlier incarnation is still in - TIME-WAIT state. Old duplicates in one direction can be avoided by - choosing the ISN to be the next unused sequence number from the - preceding connection (i.e., FIN+1); this is essentially an - - - -Jacobson, Braden & Zhang [Page 19] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - application of the scheme of Garlick, Rom, and Postel, using the - connection block in TIME-WAIT state as the connection record. - - However, the connection is still vulnerable to old duplicates in the - other direction. Mechanism (A) prevents trouble in mode F1, but - failures can arise in F2, F3, or F4; of these, F2, on short, fast - connections, is the most dangerous. - - Finally, we note TCP will operate reliably without any MSL-based - mechanisms in the following restricted domain: - - * Total data sent is less then 2**32 octets, and - - * Effective sustained rate less than 250KBps, and - - * Connection duration less than 4.55 hours. - - At the present time, the great majority of current TCP usage falls - into this restricted domain. The third component, connection - duration, is the most commonly violated. - -Security Considerations - - Security issues are not discussed in this memo. - -Authors' Addresses - - Van Jacobson - University of California - Lawrence Berkeley Laboratory - Mail Stop 46A - Berkeley, CA 94720 - - Phone: (415) 486-6411 - EMail: van@CSAM.LBL.GOV - - - Bob Braden - University of Southern California - Information Sciences Institute - 4676 Admiralty Way - Marina del Rey, CA 90292 - - Phone: (213) 822-1511 - EMail: Braden@ISI.EDU - - - - - - -Jacobson, Braden & Zhang [Page 20] - -RFC 1185 TCP over High-Speed Paths October 1990 - - - Lixia Zhang - XEROX Palo Alto Research Center - 3333 Coyote Hill Road - Palo Alto, CA 94304 - - Phone: (415) 494-4415 - EMail: lixia@PARC.XEROX.COM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Jacobson, Braden & Zhang [Page 21] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1213.txt b/ext/picotcp/RFC/rfc1213.txt deleted file mode 100644 index 50a26f5..0000000 --- a/ext/picotcp/RFC/rfc1213.txt +++ /dev/null @@ -1,3923 +0,0 @@ - - - - - - -Network Working Group K. McCloghrie -Request for Comments: 1213 Hughes LAN Systems, Inc. -Obsoletes: RFC 1158 M. Rose - Performance Systems International - Editors - March 1991 - - - Management Information Base for Network Management - of TCP/IP-based internets: - MIB-II - -Status of this Memo - - This memo defines the second version of the Management Information - Base (MIB-II) for use with network management protocols in TCP/IP- - based internets. This RFC specifies an IAB standards track protocol - for the Internet community, and requests discussion and suggestions - for improvements. Please refer to the current edition of the "IAB - Official Protocol Standards" for the standardization state and status - of this protocol. Distribution of this memo is unlimited. - -Table of Contents - - 1. Abstract............................................... 2 - 2. Introduction .......................................... 2 - 3. Changes from RFC 1156 ................................. 3 - 3.1 Deprecated Objects ................................... 3 - 3.2 Display Strings ...................................... 4 - 3.3 Physical Addresses ................................... 4 - 3.4 The System Group ..................................... 5 - 3.5 The Interfaces Group ................................. 5 - 3.6 The Address Translation Group ........................ 6 - 3.7 The IP Group ......................................... 6 - 3.8 The ICMP Group ....................................... 7 - 3.9 The TCP Group ........................................ 7 - 3.10 The UDP Group ....................................... 7 - 3.11 The EGP Group ....................................... 7 - 3.12 The Transmission Group .............................. 8 - 3.13 The SNMP Group ...................................... 8 - 3.14 Changes from RFC 1158 ................. ............. 9 - 4. Objects ............................................... 10 - 4.1 Format of Definitions ................................ 10 - 5. Overview .............................................. 10 - 6. Definitions ........................................... 12 - 6.1 Textual Conventions .................................. 12 - 6.2 Groups in MIB-II ..................................... 13 - 6.3 The System Group ..................................... 13 - - - -SNMP Working Group [Page 1] - -RFC 1213 MIB-II March 1991 - - - 6.4 The Interfaces Group ................................. 16 - 6.5 The Address Translation Group ........................ 23 - 6.6 The IP Group ......................................... 26 - 6.7 The ICMP Group ....................................... 41 - 6.8 The TCP Group ........................................ 46 - 6.9 The UDP Group ........................................ 52 - 6.10 The EGP Group ....................................... 54 - 6.11 The Transmission Group .............................. 60 - 6.12 The SNMP Group ...................................... 60 - 7. Acknowledgements ...................................... 67 - 8. References ............................................ 69 - 9. Security Considerations ............................... 70 - 10. Authors' Addresses ................................... 70 - -1. Abstract - - This memo defines the second version of the Management Information - Base (MIB-II) for use with network management protocols in TCP/IP- - based internets. In particular, together with its companion memos - which describe the structure of management information (RFC 1155) - along with the network management protocol (RFC 1157) for TCP/IP- - based internets, these documents provide a simple, workable - architecture and system for managing TCP/IP-based internets and in - particular the Internet community. - -2. Introduction - - As reported in RFC 1052, IAB Recommendations for the Development of - Internet Network Management Standards [1], a two-prong strategy for - network management of TCP/IP-based internets was undertaken. In the - short-term, the Simple Network Management Protocol (SNMP) was to be - used to manage nodes in the Internet community. In the long-term, - the use of the OSI network management framework was to be examined. - Two documents were produced to define the management information: RFC - 1065, which defined the Structure of Management Information (SMI) - [2], and RFC 1066, which defined the Management Information Base - (MIB) [3]. Both of these documents were designed so as to be - compatible with both the SNMP and the OSI network management - framework. - - This strategy was quite successful in the short-term: Internet-based - network management technology was fielded, by both the research and - commercial communities, within a few months. As a result of this, - portions of the Internet community became network manageable in a - timely fashion. - - As reported in RFC 1109, Report of the Second Ad Hoc Network - Management Review Group [4], the requirements of the SNMP and the OSI - - - -SNMP Working Group [Page 2] - -RFC 1213 MIB-II March 1991 - - - network management frameworks were more different than anticipated. - As such, the requirement for compatibility between the SMI/MIB and - both frameworks was suspended. This action permitted the operational - network management framework, the SNMP, to respond to new operational - needs in the Internet community by producing this document. - - As such, the current network management framework for TCP/IP- based - internets consists of: Structure and Identification of Management - Information for TCP/IP-based internets, RFC 1155 [12], which - describes how managed objects contained in the MIB are defined; - Management Information Base for Network Management of TCP/IP-based - internets: MIB-II, this memo, which describes the managed objects - contained in the MIB (and supercedes RFC 1156 [13]); and, the Simple - Network Management Protocol, RFC 1098 [5], which defines the protocol - used to manage these objects. - -3. Changes from RFC 1156 - - Features of this MIB include: - - (1) incremental additions to reflect new operational - requirements; - - (2) upwards compatibility with the SMI/MIB and the SNMP; - - (3) improved support for multi-protocol entities; and, - - (4) textual clean-up of the MIB to improve clarity and - readability. - - The objects defined in MIB-II have the OBJECT IDENTIFIER prefix: - - mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } - - which is identical to the prefix used in MIB-I. - -3.1. Deprecated Objects - - In order to better prepare implementors for future changes in the - MIB, a new term "deprecated" may be used when describing an object. - A deprecated object in the MIB is one which must be supported, but - one which will most likely be removed from the next version of the - MIB (e.g., MIB-III). - - MIB-II marks one object as being deprecated: - - atTable - - - - -SNMP Working Group [Page 3] - -RFC 1213 MIB-II March 1991 - - - As a result of deprecating the atTable object, the entire Address - Translation group is deprecated. - - Note that no functionality is lost with the deprecation of these - objects: new objects providing equivalent or superior functionality - are defined in MIB-II. - -3.2. Display Strings - - In the past, there have been misinterpretations of the MIB as to when - a string of octets should contain printable characters, meant to be - displayed to a human. As a textual convention in the MIB, the - datatype - - DisplayString ::= - OCTET STRING - - is introduced. A DisplayString is restricted to the NVT ASCII - character set, as defined in pages 10-11 of [6]. - - The following objects are now defined in terms of DisplayString: - - sysDescr - ifDescr - - It should be noted that this change has no effect on either the - syntax nor semantics of these objects. The use of the DisplayString - notation is merely an artifact of the explanatory method used in - MIB-II and future MIBs. - - Further it should be noted that any object defined in terms of OCTET - STRING may contain arbitrary binary data, in which each octet may - take any value from 0 to 255 (decimal). - -3.3. Physical Addresses - - As a further, textual convention in the MIB, the datatype - - PhysAddress ::= - OCTET STRING - - is introduced to represent media- or physical-level addresses. - - The following objects are now defined in terms of PhysAddress: - - ifPhysAddress - atPhysAddress - ipNetToMediaPhysAddress - - - -SNMP Working Group [Page 4] - -RFC 1213 MIB-II March 1991 - - - It should be noted that this change has no effect on either the - syntax nor semantics of these objects. The use of the PhysAddress - notation is merely an artifact of the explanatory method used in - MIB-II and future MIBs. - -3.4. The System Group - - Four new objects are added to this group: - - sysContact - sysName - sysLocation - sysServices - - These provide contact, administrative, location, and service - information regarding the managed node. - -3.5. The Interfaces Group - - The definition of the ifNumber object was incorrect, as it required - all interfaces to support IP. (For example, devices without IP, such - as MAC-layer bridges, could not be managed if this definition was - strictly followed.) The description of the ifNumber object is - changed accordingly. - - The ifTable object was mistaken marked as read-write, it has been - (correctly) re-designated as not-accessible. In addition, several - new values have been added to the ifType column in the ifTable - object: - - ppp(23) - softwareLoopback(24) - eon(25) - ethernet-3Mbit(26) - nsip(27) - slip(28) - ultra(29) - ds3(30) - sip(31) - frame-relay(32) - - Finally, a new column has been added to the ifTable object: - - ifSpecific - - which provides information about information specific to the media - being used to realize the interface. - - - - -SNMP Working Group [Page 5] - -RFC 1213 MIB-II March 1991 - - -3.6. The Address Translation Group - - In MIB-I this group contained a table which permitted mappings from - network addresses (e.g., IP addresses) to physical addresses (e.g., - MAC addresses). Experience has shown that efficient implementations - of this table make two assumptions: a single network protocol - environment, and mappings occur only from network address to physical - address. - - The need to support multi-protocol nodes (e.g., those with both the - IP and CLNP active), and the need to support the inverse mapping - (e.g., for ES-IS), have invalidated both of these assumptions. As - such, the atTable object is declared deprecated. - - In order to meet both the multi-protocol and inverse mapping - requirements, MIB-II and its successors will allocate up to two - address translation tables inside each network protocol group. That - is, the IP group will contain one address translation table, for - going from IP addresses to physical addresses. Similarly, when a - document defining MIB objects for the CLNP is produced (e.g., [7]), - it will contain two tables, for mappings in both directions, as this - is required for full functionality. - - It should be noted that the choice of two tables (one for each - direction of mapping) provides for ease of implementation in many - cases, and does not introduce undue burden on implementations which - realize the address translation abstraction through a single internal - table. - -3.7. The IP Group - - The access attribute of the variable ipForwarding has been changed - from read-only to read-write. - - In addition, there is a new column to the ipAddrTable object, - - ipAdEntReasmMaxSize - - which keeps track of the largest IP datagram that can be re-assembled - on a particular interface. - - The descriptor of the ipRoutingTable object has been changed to - ipRouteTable for consistency with the other IP routing objects. - There are also three new columns in the ipRouteTable object, - - ipRouteMask - ipRouteMetric5 - ipRouteInfo - - - -SNMP Working Group [Page 6] - -RFC 1213 MIB-II March 1991 - - - the first is used for IP routing subsystems that support arbitrary - subnet masks, and the latter two are IP routing protocol-specific. - - Two new objects are added to the IP group: - - ipNetToMediaTable - ipRoutingDiscards - - the first is the address translation table for the IP group - (providing identical functionality to the now deprecated atTable in - the address translation group), and the latter provides information - when routes are lost due to a lack of buffer space. - -3.8. The ICMP Group - - There are no changes to this group. - -3.9. The TCP Group - - Two new variables are added: - - tcpInErrs - tcpOutRsts - - which keep track of the number of incoming TCP segments in error and - the number of resets generated by a TCP. - -3.10. The UDP Group - - A new table: - - udpTable - - is added. - -3.11. The EGP Group - - Experience has indicated a need for additional objects that are - useful in EGP monitoring. In addition to making several additions to - the egpNeighborTable object, i.e., - - egpNeighAs - egpNeighInMsgs - egpNeighInErrs - egpNeighOutMsgs - egpNeighOutErrs - egpNeighInErrMsgs - egpNeighOutErrMsgs - - - -SNMP Working Group [Page 7] - -RFC 1213 MIB-II March 1991 - - - egpNeighStateUps - egpNeighStateDowns - egpNeighIntervalHello - egpNeighIntervalPoll - egpNeighMode - egpNeighEventTrigger - - a new variable is added: - - egpAs - - which gives the autonomous system associated with this EGP entity. - -3.12. The Transmission Group - - MIB-I was lacking in that it did not distinguish between different - types of transmission media. A new group, the Transmission group, is - allocated for this purpose: - - transmission OBJECT IDENTIFIER ::= { mib-2 10 } - - When Internet-standard definitions for managing transmission media - are defined, the transmission group is used to provide a prefix for - the names of those objects. - - Typically, such definitions reside in the experimental portion of the - MIB until they are "proven", then as a part of the Internet - standardization process, the definitions are accordingly elevated and - a new object identifier, under the transmission group is defined. By - convention, the name assigned is: - - type OBJECT IDENTIFIER ::= { transmission number } - - where "type" is the symbolic value used for the media in the ifType - column of the ifTable object, and "number" is the actual integer - value corresponding to the symbol. - -3.13. The SNMP Group - - The application-oriented working groups of the IETF have been tasked - to be receptive towards defining MIB variables specific to their - respective applications. - - For the SNMP, it is useful to have statistical information. A new - group, the SNMP group, is allocated for this purpose: - - snmp OBJECT IDENTIFIER ::= { mib-2 11 } - - - - -SNMP Working Group [Page 8] - -RFC 1213 MIB-II March 1991 - - -3.14. Changes from RFC 1158 - - Features of this MIB include: - - (1) The managed objects in this document have been defined - using the conventions defined in the Internet-standard - SMI, as amended by the extensions specified in [14]. It - must be emphasized that definitions made using these - extensions are semantically identically to those in RFC - 1158. - - (2) The PhysAddress textual convention has been introduced to - represent media addresses. - - (3) The ACCESS clause of sysLocation is now read-write. - - (4) The definition of sysServices has been clarified. - - (5) New ifType values (29-32) have been defined. In - addition, the textual-descriptor for the DS1 and E1 - interface types has been corrected. - - (6) The definition of ipForwarding has been clarified. - - (7) The definition of ipRouteType has been clarified. - - (8) The ipRouteMetric5 and ipRouteInfo objects have been - defined. - - (9) The ACCESS clause of tcpConnState is now read-write, to - support deletion of the TCB associated with a TCP - connection. The definition of this object has been - clarified to explain this usage. - - (10) The definition of egpNeighEventTrigger has been - clarified. - - (11) The definition of several of the variables in the new - snmp group have been clarified. In addition, the - snmpInBadTypes and snmpOutReadOnlys objects are no longer - present. (However, the object identifiers associated - with those objects are reserved to prevent future use.) - - (12) The definition of snmpInReadOnlys has been clarified. - - (13) The textual descriptor of the snmpEnableAuthTraps has - been changed to snmpEnableAuthenTraps, and the definition - has been clarified. - - - -SNMP Working Group [Page 9] - -RFC 1213 MIB-II March 1991 - - - (14) The ipRoutingDiscards object was added. - - (15) The optional use of an implementation-dependent, small - positive integer was disallowed when identifying - instances of the IP address and routing tables. - -4. Objects - - Managed objects are accessed via a virtual information store, termed - the Management Information Base or MIB. Objects in the MIB are - defined using the subset of Abstract Syntax Notation One (ASN.1) [8] - defined in the SMI. In particular, each object has a name, a syntax, - and an encoding. The name is an object identifier, an - administratively assigned name, which specifies an object type. The - object type together with an object instance serves to uniquely - identify a specific instantiation of the object. For human - convenience, we often use a textual string, termed the OBJECT - DESCRIPTOR, to also refer to the object type. - - The syntax of an object type defines the abstract data structure - corresponding to that object type. The ASN.1 language is used for - this purpose. However, the SMI [12] purposely restricts the ASN.1 - constructs which may be used. These restrictions are explicitly made - for simplicity. - - The encoding of an object type is simply how that object type is - represented using the object type's syntax. Implicitly tied to the - notion of an object type's syntax and encoding is how the object type - is represented when being transmitted on the network. - - The SMI specifies the use of the basic encoding rules of ASN.1 [9], - subject to the additional requirements imposed by the SNMP. - -4.1. Format of Definitions - - Section 6 contains contains the specification of all object types - contained in this MIB module. The object types are defined using the - conventions defined in the SMI, as amended by the extensions - specified in [14]. - -5. Overview - - Consistent with the IAB directive to produce simple, workable systems - in the short-term, the list of managed objects defined here, has been - derived by taking only those elements which are considered essential. - - This approach of taking only the essential objects is NOT - restrictive, since the SMI defined in the companion memo provides - - - -SNMP Working Group [Page 10] - -RFC 1213 MIB-II March 1991 - - - three extensibility mechanisms: one, the addition of new standard - objects through the definitions of new versions of the MIB; two, the - addition of widely-available but non-standard objects through the - experimental subtree; and three, the addition of private objects - through the enterprises subtree. Such additional objects can not - only be used for vendor-specific elements, but also for - experimentation as required to further the knowledge of which other - objects are essential. - - The design of MIB-II is heavily influenced by the first extensibility - mechanism. Several new variables have been added based on - operational experience and need. Based on this, the criteria for - including an object in MIB-II are remarkably similar to the MIB-I - criteria: - - (1) An object needed to be essential for either fault or - configuration management. - - (2) Only weak control objects were permitted (by weak, it is - meant that tampering with them can do only limited - damage). This criterion reflects the fact that the - current management protocols are not sufficiently secure - to do more powerful control operations. - - (3) Evidence of current use and utility was required. - - (4) In MIB-I, an attempt was made to limit the number of - objects to about 100 to make it easier for vendors to - fully instrument their software. In MIB-II, this limit - was raised given the wide technological base now - implementing MIB-I. - - (5) To avoid redundant variables, it was required that no - object be included that can be derived from others in the - MIB. - - (6) Implementation specific objects (e.g., for BSD UNIX) were - excluded. - - (7) It was agreed to avoid heavily instrumenting critical - sections of code. The general guideline was one counter - per critical section per layer. - - MIB-II, like its predecessor, the Internet-standard MIB, contains - only essential elements. There is no need to allow individual - objects to be optional. Rather, the objects are arranged into the - following groups: - - - - -SNMP Working Group [Page 11] - -RFC 1213 MIB-II March 1991 - - - - System - - Interfaces - - Address Translation (deprecated) - - IP - - ICMP - - TCP - - UDP - - EGP - - Transmission - - SNMP - - These groups are the basic unit of conformance: This method is as - follows: if the semantics of a group is applicable to an - implementation, then it must implement all objects in that group. - For example, an implementation must implement the EGP group if and - only if it implements the EGP. - - There are two reasons for defining these groups: to provide a means - of assigning object identifiers; and, to provide a method for - implementations of managed agents to know which objects they must - implement. - -6. Definitions - - RFC1213-MIB DEFINITIONS ::= BEGIN - - IMPORTS - mgmt, NetworkAddress, IpAddress, Counter, Gauge, - TimeTicks - FROM RFC1155-SMI - OBJECT-TYPE - FROM RFC-1212; - - -- This MIB module uses the extended OBJECT-TYPE macro as - -- defined in [14]; - - - -- MIB-II (same prefix as MIB-I) - - mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } - - -- textual conventions - - DisplayString ::= - OCTET STRING - -- This data type is used to model textual information taken - -- from the NVT ASCII character set. By convention, objects - -- with this syntax are declared as having - - - -SNMP Working Group [Page 12] - -RFC 1213 MIB-II March 1991 - - - -- - -- SIZE (0..255) - - PhysAddress ::= - OCTET STRING - -- This data type is used to model media addresses. For many - -- types of media, this will be in a binary representation. - -- For example, an ethernet address would be represented as - -- a string of 6 octets. - - - -- groups in MIB-II - - system OBJECT IDENTIFIER ::= { mib-2 1 } - - interfaces OBJECT IDENTIFIER ::= { mib-2 2 } - - at OBJECT IDENTIFIER ::= { mib-2 3 } - - ip OBJECT IDENTIFIER ::= { mib-2 4 } - - icmp OBJECT IDENTIFIER ::= { mib-2 5 } - - tcp OBJECT IDENTIFIER ::= { mib-2 6 } - - udp OBJECT IDENTIFIER ::= { mib-2 7 } - - egp OBJECT IDENTIFIER ::= { mib-2 8 } - - -- historical (some say hysterical) - -- cmot OBJECT IDENTIFIER ::= { mib-2 9 } - - transmission OBJECT IDENTIFIER ::= { mib-2 10 } - - snmp OBJECT IDENTIFIER ::= { mib-2 11 } - - - -- the System group - - -- Implementation of the System group is mandatory for all - -- systems. If an agent is not configured to have a value - -- for any of these variables, a string of length 0 is - -- returned. - - sysDescr OBJECT-TYPE - SYNTAX DisplayString (SIZE (0..255)) - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 13] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "A textual description of the entity. This value - should include the full name and version - identification of the system's hardware type, - software operating-system, and networking - software. It is mandatory that this only contain - printable ASCII characters." - ::= { system 1 } - - sysObjectID OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The vendor's authoritative identification of the - network management subsystem contained in the - entity. This value is allocated within the SMI - enterprises subtree (1.3.6.1.4.1) and provides an - easy and unambiguous means for determining `what - kind of box' is being managed. For example, if - vendor `Flintstones, Inc.' was assigned the - subtree 1.3.6.1.4.1.4242, it could assign the - identifier 1.3.6.1.4.1.4242.1.1 to its `Fred - Router'." - ::= { system 2 } - - sysUpTime OBJECT-TYPE - SYNTAX TimeTicks - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The time (in hundredths of a second) since the - network management portion of the system was last - re-initialized." - ::= { system 3 } - - sysContact OBJECT-TYPE - SYNTAX DisplayString (SIZE (0..255)) - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The textual identification of the contact person - for this managed node, together with information - on how to contact this person." - ::= { system 4 } - - sysName OBJECT-TYPE - SYNTAX DisplayString (SIZE (0..255)) - - - -SNMP Working Group [Page 14] - -RFC 1213 MIB-II March 1991 - - - ACCESS read-write - STATUS mandatory - DESCRIPTION - "An administratively-assigned name for this - managed node. By convention, this is the node's - fully-qualified domain name." - ::= { system 5 } - - sysLocation OBJECT-TYPE - SYNTAX DisplayString (SIZE (0..255)) - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The physical location of this node (e.g., - `telephone closet, 3rd floor')." - ::= { system 6 } - - sysServices OBJECT-TYPE - SYNTAX INTEGER (0..127) - ACCESS read-only - STATUS mandatory - DESCRIPTION - "A value which indicates the set of services that - this entity primarily offers. - - The value is a sum. This sum initially takes the - value zero, Then, for each layer, L, in the range - 1 through 7, that this node performs transactions - for, 2 raised to (L - 1) is added to the sum. For - example, a node which performs primarily routing - functions would have a value of 4 (2^(3-1)). In - contrast, a node which is a host offering - application services would have a value of 72 - (2^(4-1) + 2^(7-1)). Note that in the context of - the Internet suite of protocols, values should be - calculated accordingly: - - layer functionality - 1 physical (e.g., repeaters) - 2 datalink/subnetwork (e.g., bridges) - 3 internet (e.g., IP gateways) - 4 end-to-end (e.g., IP hosts) - 7 applications (e.g., mail relays) - - For systems including OSI protocols, layers 5 and - 6 may also be counted." - ::= { system 7 } - - - - -SNMP Working Group [Page 15] - -RFC 1213 MIB-II March 1991 - - - -- the Interfaces group - - -- Implementation of the Interfaces group is mandatory for - -- all systems. - - ifNumber OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of network interfaces (regardless of - their current state) present on this system." - ::= { interfaces 1 } - - - -- the Interfaces table - - -- The Interfaces table contains information on the entity's - -- interfaces. Each interface is thought of as being - -- attached to a `subnetwork'. Note that this term should - -- not be confused with `subnet' which refers to an - -- addressing partitioning scheme used in the Internet suite - -- of protocols. - - ifTable OBJECT-TYPE - SYNTAX SEQUENCE OF IfEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "A list of interface entries. The number of - entries is given by the value of ifNumber." - ::= { interfaces 2 } - - ifEntry OBJECT-TYPE - SYNTAX IfEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "An interface entry containing objects at the - subnetwork layer and below for a particular - interface." - INDEX { ifIndex } - ::= { ifTable 1 } - - IfEntry ::= - SEQUENCE { - ifIndex - INTEGER, - - - -SNMP Working Group [Page 16] - -RFC 1213 MIB-II March 1991 - - - ifDescr - DisplayString, - ifType - INTEGER, - ifMtu - INTEGER, - ifSpeed - Gauge, - ifPhysAddress - PhysAddress, - ifAdminStatus - INTEGER, - ifOperStatus - INTEGER, - ifLastChange - TimeTicks, - ifInOctets - Counter, - ifInUcastPkts - Counter, - ifInNUcastPkts - Counter, - ifInDiscards - Counter, - ifInErrors - Counter, - ifInUnknownProtos - Counter, - ifOutOctets - Counter, - ifOutUcastPkts - Counter, - ifOutNUcastPkts - Counter, - ifOutDiscards - Counter, - ifOutErrors - Counter, - ifOutQLen - Gauge, - ifSpecific - OBJECT IDENTIFIER - } - - ifIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 17] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "A unique value for each interface. Its value - ranges between 1 and the value of ifNumber. The - value for each interface must remain constant at - least from one re-initialization of the entity's - network management system to the next re- - initialization." - ::= { ifEntry 1 } - - ifDescr OBJECT-TYPE - SYNTAX DisplayString (SIZE (0..255)) - ACCESS read-only - STATUS mandatory - DESCRIPTION - "A textual string containing information about the - interface. This string should include the name of - the manufacturer, the product name and the version - of the hardware interface." - ::= { ifEntry 2 } - - ifType OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - regular1822(2), - hdh1822(3), - ddn-x25(4), - rfc877-x25(5), - ethernet-csmacd(6), - iso88023-csmacd(7), - iso88024-tokenBus(8), - iso88025-tokenRing(9), - iso88026-man(10), - starLan(11), - proteon-10Mbit(12), - proteon-80Mbit(13), - hyperchannel(14), - fddi(15), - lapb(16), - sdlc(17), - ds1(18), -- T-1 - e1(19), -- european equiv. of T-1 - basicISDN(20), - primaryISDN(21), -- proprietary serial - propPointToPointSerial(22), - ppp(23), - softwareLoopback(24), - eon(25), -- CLNP over IP [11] - ethernet-3Mbit(26), - - - -SNMP Working Group [Page 18] - -RFC 1213 MIB-II March 1991 - - - nsip(27), -- XNS over IP - slip(28), -- generic SLIP - ultra(29), -- ULTRA technologies - ds3(30), -- T-3 - sip(31), -- SMDS - frame-relay(32) - } - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The type of interface, distinguished according to - the physical/link protocol(s) immediately `below' - the network layer in the protocol stack." - ::= { ifEntry 3 } - - ifMtu OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The size of the largest datagram which can be - sent/received on the interface, specified in - octets. For interfaces that are used for - transmitting network datagrams, this is the size - of the largest network datagram that can be sent - on the interface." - ::= { ifEntry 4 } - - ifSpeed OBJECT-TYPE - SYNTAX Gauge - ACCESS read-only - STATUS mandatory - DESCRIPTION - "An estimate of the interface's current bandwidth - in bits per second. For interfaces which do not - vary in bandwidth or for those where no accurate - estimation can be made, this object should contain - the nominal bandwidth." - ::= { ifEntry 5 } - - ifPhysAddress OBJECT-TYPE - SYNTAX PhysAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The interface's address at the protocol layer - immediately `below' the network layer in the - protocol stack. For interfaces which do not have - - - -SNMP Working Group [Page 19] - -RFC 1213 MIB-II March 1991 - - - such an address (e.g., a serial line), this object - should contain an octet string of zero length." - ::= { ifEntry 6 } - - ifAdminStatus OBJECT-TYPE - SYNTAX INTEGER { - up(1), -- ready to pass packets - down(2), - testing(3) -- in some test mode - } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The desired state of the interface. The - testing(3) state indicates that no operational - packets can be passed." - ::= { ifEntry 7 } - - ifOperStatus OBJECT-TYPE - SYNTAX INTEGER { - up(1), -- ready to pass packets - down(2), - testing(3) -- in some test mode - } - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The current operational state of the interface. - The testing(3) state indicates that no operational - packets can be passed." - ::= { ifEntry 8 } - - ifLastChange OBJECT-TYPE - SYNTAX TimeTicks - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The value of sysUpTime at the time the interface - entered its current operational state. If the - current state was entered prior to the last re- - initialization of the local network management - subsystem, then this object contains a zero - value." - ::= { ifEntry 9 } - - ifInOctets OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - - - -SNMP Working Group [Page 20] - -RFC 1213 MIB-II March 1991 - - - STATUS mandatory - DESCRIPTION - "The total number of octets received on the - interface, including framing characters." - ::= { ifEntry 10 } - - ifInUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of subnetwork-unicast packets - delivered to a higher-layer protocol." - ::= { ifEntry 11 } - - ifInNUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of non-unicast (i.e., subnetwork- - broadcast or subnetwork-multicast) packets - delivered to a higher-layer protocol." - ::= { ifEntry 12 } - - ifInDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "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." - ::= { ifEntry 13 } - - ifInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of inbound packets that contained - errors preventing them from being deliverable to a - higher-layer protocol." - ::= { ifEntry 14 } - - - - -SNMP Working Group [Page 21] - -RFC 1213 MIB-II March 1991 - - - ifInUnknownProtos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of packets received via the interface - which were discarded because of an unknown or - unsupported protocol." - ::= { ifEntry 15 } - - ifOutOctets OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of octets transmitted out of the - interface, including framing characters." - ::= { ifEntry 16 } - - ifOutUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of packets that higher-level - protocols requested be transmitted to a - subnetwork-unicast address, including those that - were discarded or not sent." - ::= { ifEntry 17 } - - ifOutNUcastPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of packets that higher-level - protocols requested be transmitted to a non- - unicast (i.e., a subnetwork-broadcast or - subnetwork-multicast) address, including those - that were discarded or not sent." - ::= { ifEntry 18 } - - ifOutDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of outbound packets which were chosen - - - -SNMP Working Group [Page 22] - -RFC 1213 MIB-II March 1991 - - - 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." - ::= { ifEntry 19 } - - ifOutErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of outbound packets that could not be - transmitted because of errors." - ::= { ifEntry 20 } - - ifOutQLen OBJECT-TYPE - SYNTAX Gauge - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The length of the output packet queue (in - packets)." - ::= { ifEntry 21 } - - ifSpecific OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "A reference to MIB definitions specific to the - particular media being used to realize the - interface. For example, if the interface is - realized by an ethernet, then the value of this - object refers to a document defining objects - specific to ethernet. If this information is not - present, its value should be set to the OBJECT - IDENTIFIER { 0 0 }, which is a syntatically valid - object identifier, and any conformant - implementation of ASN.1 and BER must be able to - generate and recognize this value." - ::= { ifEntry 22 } - - - -- the Address Translation group - - -- Implementation of the Address Translation group is - -- mandatory for all systems. Note however that this group - -- is deprecated by MIB-II. That is, it is being included - - - -SNMP Working Group [Page 23] - -RFC 1213 MIB-II March 1991 - - - -- solely for compatibility with MIB-I nodes, and will most - -- likely be excluded from MIB-III nodes. From MIB-II and - -- onwards, each network protocol group contains its own - -- address translation tables. - - -- The Address Translation group contains one table which is - -- the union across all interfaces of the translation tables - -- for converting a NetworkAddress (e.g., an IP address) into - -- a subnetwork-specific address. For lack of a better term, - -- this document refers to such a subnetwork-specific address - -- as a `physical' address. - - -- Examples of such translation tables are: for broadcast - -- media where ARP is in use, the translation table is - -- equivalent to the ARP cache; or, on an X.25 network where - -- non-algorithmic translation to X.121 addresses is - -- required, the translation table contains the - -- NetworkAddress to X.121 address equivalences. - - atTable OBJECT-TYPE - SYNTAX SEQUENCE OF AtEntry - ACCESS not-accessible - STATUS deprecated - DESCRIPTION - "The Address Translation tables contain the - NetworkAddress to `physical' address equivalences. - Some interfaces do not use translation tables for - determining address equivalences (e.g., DDN-X.25 - has an algorithmic method); if all interfaces are - of this type, then the Address Translation table - is empty, i.e., has zero entries." - ::= { at 1 } - - atEntry OBJECT-TYPE - SYNTAX AtEntry - ACCESS not-accessible - STATUS deprecated - DESCRIPTION - "Each entry contains one NetworkAddress to - `physical' address equivalence." - INDEX { atIfIndex, - atNetAddress } - ::= { atTable 1 } - - AtEntry ::= - SEQUENCE { - atIfIndex - INTEGER, - - - -SNMP Working Group [Page 24] - -RFC 1213 MIB-II March 1991 - - - atPhysAddress - PhysAddress, - atNetAddress - NetworkAddress - } - - atIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS deprecated - DESCRIPTION - "The interface on which this entry's equivalence - is effective. The interface identified by a - particular value of this index is the same - interface as identified by the same value of - ifIndex." - ::= { atEntry 1 } - - atPhysAddress OBJECT-TYPE - SYNTAX PhysAddress - ACCESS read-write - STATUS deprecated - DESCRIPTION - "The media-dependent `physical' address. - - Setting this object to a null string (one of zero - length) has the effect of invaliding the - corresponding entry in the atTable object. That - is, it effectively dissasociates the interface - identified with said entry from the mapping - identified with said entry. It is an - implementation-specific matter as to whether the - agent removes an invalidated entry from the table. - Accordingly, management stations must be prepared - to receive tabular information from agents that - corresponds to entries not currently in use. - Proper interpretation of such entries requires - examination of the relevant atPhysAddress object." - ::= { atEntry 2 } - - atNetAddress OBJECT-TYPE - SYNTAX NetworkAddress - ACCESS read-write - STATUS deprecated - DESCRIPTION - "The NetworkAddress (e.g., the IP address) - corresponding to the media-dependent `physical' - address." - - - -SNMP Working Group [Page 25] - -RFC 1213 MIB-II March 1991 - - - ::= { atEntry 3 } - - - -- the IP group - - -- Implementation of the IP group is mandatory for all - -- systems. - - ipForwarding OBJECT-TYPE - SYNTAX INTEGER { - forwarding(1), -- acting as a gateway - not-forwarding(2) -- NOT acting as a gateway - } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The indication of whether this entity is acting - as an IP gateway in respect to the forwarding of - datagrams received by, but not addressed to, this - entity. IP gateways forward datagrams. IP hosts - do not (except those source-routed via the host). - - Note that for some managed nodes, this object may - take on only a subset of the values possible. - Accordingly, it is appropriate for an agent to - return a `badValue' response if a management - station attempts to change this object to an - inappropriate value." - ::= { ip 1 } - - ipDefaultTTL OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The default value inserted into the Time-To-Live - field of the IP header of datagrams originated at - this entity, whenever a TTL value is not supplied - by the transport layer protocol." - ::= { ip 2 } - - ipInReceives OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of input datagrams received from - interfaces, including those received in error." - - - -SNMP Working Group [Page 26] - -RFC 1213 MIB-II March 1991 - - - ::= { ip 3 } - - ipInHdrErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of input datagrams discarded due to - errors in their IP headers, including bad - checksums, version number mismatch, other format - errors, time-to-live exceeded, errors discovered - in processing their IP options, etc." - ::= { ip 4 } - - ipInAddrErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of input datagrams discarded because - the IP address in their IP header's destination - field was not a valid address to be received at - this entity. This count includes invalid - addresses (e.g., 0.0.0.0) and addresses of - unsupported Classes (e.g., Class E). For entities - which are not IP Gateways and therefore do not - forward datagrams, this counter includes datagrams - discarded because the destination address was not - a local address." - ::= { ip 5 } - - ipForwDatagrams OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of input datagrams for which this - entity was not their final IP destination, as a - result of which an attempt was made to find a - route to forward them to that final destination. - In entities which do not act as IP Gateways, this - counter will include only those packets which were - Source-Routed via this entity, and the Source- - Route option processing was successful." - ::= { ip 6 } - - ipInUnknownProtos OBJECT-TYPE - SYNTAX Counter - - - -SNMP Working Group [Page 27] - -RFC 1213 MIB-II March 1991 - - - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of locally-addressed datagrams - received successfully but discarded because of an - unknown or unsupported protocol." - ::= { ip 7 } - - ipInDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of input IP datagrams for which no - problems were encountered to prevent their - continued processing, but which were discarded - (e.g., for lack of buffer space). Note that this - counter does not include any datagrams discarded - while awaiting re-assembly." - ::= { ip 8 } - - ipInDelivers OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of input datagrams successfully - delivered to IP user-protocols (including ICMP)." - ::= { ip 9 } - - ipOutRequests OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of IP datagrams which local IP - user-protocols (including ICMP) supplied to IP in - requests for transmission. Note that this counter - does not include any datagrams counted in - ipForwDatagrams." - ::= { ip 10 } - - ipOutDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of output IP datagrams for which no - - - -SNMP Working Group [Page 28] - -RFC 1213 MIB-II March 1991 - - - problem was encountered to prevent their - transmission to their destination, but which were - discarded (e.g., for lack of buffer space). Note - that this counter would include datagrams counted - in ipForwDatagrams if any such packets met this - (discretionary) discard criterion." - ::= { ip 11 } - - ipOutNoRoutes OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of IP datagrams discarded because no - route could be found to transmit them to their - destination. Note that this counter includes any - packets counted in ipForwDatagrams which meet this - `no-route' criterion. Note that this includes any - datagarms which a host cannot route because all of - its default gateways are down." - ::= { ip 12 } - - ipReasmTimeout OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The maximum number of seconds which received - fragments are held while they are awaiting - reassembly at this entity." - ::= { ip 13 } - - ipReasmReqds OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of IP fragments received which needed - to be reassembled at this entity." - ::= { ip 14 } - - ipReasmOKs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of IP datagrams successfully re- - assembled." - - - -SNMP Working Group [Page 29] - -RFC 1213 MIB-II March 1991 - - - ::= { ip 15 } - - ipReasmFails OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of failures detected by the IP re- - assembly algorithm (for whatever reason: timed - out, errors, etc). Note that this is not - necessarily a count of discarded IP fragments - since some algorithms (notably the algorithm in - RFC 815) can lose track of the number of fragments - by combining them as they are received." - ::= { ip 16 } - - ipFragOKs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of IP datagrams that have been - successfully fragmented at this entity." - ::= { ip 17 } - - ipFragFails OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of IP datagrams that have been - discarded because they needed to be fragmented at - this entity but could not be, e.g., because their - Don't Fragment flag was set." - ::= { ip 18 } - - ipFragCreates OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of IP datagram fragments that have - been generated as a result of fragmentation at - this entity." - ::= { ip 19 } - - - - - - -SNMP Working Group [Page 30] - -RFC 1213 MIB-II March 1991 - - - -- the IP address table - - -- The IP address table contains this entity's IP addressing - -- information. - - ipAddrTable OBJECT-TYPE - SYNTAX SEQUENCE OF IpAddrEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "The table of addressing information relevant to - this entity's IP addresses." - ::= { ip 20 } - - ipAddrEntry OBJECT-TYPE - SYNTAX IpAddrEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "The addressing information for one of this - entity's IP addresses." - INDEX { ipAdEntAddr } - ::= { ipAddrTable 1 } - - IpAddrEntry ::= - SEQUENCE { - ipAdEntAddr - IpAddress, - ipAdEntIfIndex - INTEGER, - ipAdEntNetMask - IpAddress, - ipAdEntBcastAddr - INTEGER, - ipAdEntReasmMaxSize - INTEGER (0..65535) - } - - ipAdEntAddr OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The IP address to which this entry's addressing - information pertains." - ::= { ipAddrEntry 1 } - - - - - -SNMP Working Group [Page 31] - -RFC 1213 MIB-II March 1991 - - - ipAdEntIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The index value which uniquely identifies the - interface to which this entry is applicable. The - interface identified by a particular value of this - index is the same interface as identified by the - same value of ifIndex." - ::= { ipAddrEntry 2 } - - ipAdEntNetMask OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The subnet mask associated with the IP address of - this entry. The value of the mask is an IP - address with all the network bits set to 1 and all - the hosts bits set to 0." - ::= { ipAddrEntry 3 } - - ipAdEntBcastAddr OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The value of the least-significant bit in the IP - broadcast address used for sending datagrams on - the (logical) interface associated with the IP - address of this entry. For example, when the - Internet standard all-ones broadcast address is - used, the value will be 1. This value applies to - both the subnet and network broadcasts addresses - used by the entity on this (logical) interface." - ::= { ipAddrEntry 4 } - - ipAdEntReasmMaxSize OBJECT-TYPE - SYNTAX INTEGER (0..65535) - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The size of the largest IP datagram which this - entity can re-assemble from incoming IP fragmented - datagrams received on this interface." - ::= { ipAddrEntry 5 } - - - - -SNMP Working Group [Page 32] - -RFC 1213 MIB-II March 1991 - - - -- the IP routing table - - -- The IP routing table contains an entry for each route - -- presently known to this entity. - - ipRouteTable OBJECT-TYPE - SYNTAX SEQUENCE OF IpRouteEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "This entity's IP Routing table." - ::= { ip 21 } - - ipRouteEntry OBJECT-TYPE - SYNTAX IpRouteEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "A route to a particular destination." - INDEX { ipRouteDest } - ::= { ipRouteTable 1 } - - IpRouteEntry ::= - SEQUENCE { - ipRouteDest - IpAddress, - ipRouteIfIndex - INTEGER, - ipRouteMetric1 - INTEGER, - ipRouteMetric2 - INTEGER, - ipRouteMetric3 - INTEGER, - ipRouteMetric4 - INTEGER, - ipRouteNextHop - IpAddress, - ipRouteType - INTEGER, - ipRouteProto - INTEGER, - ipRouteAge - INTEGER, - ipRouteMask - IpAddress, - ipRouteMetric5 - INTEGER, - - - -SNMP Working Group [Page 33] - -RFC 1213 MIB-II March 1991 - - - ipRouteInfo - OBJECT IDENTIFIER - } - - ipRouteDest OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The destination IP address of this route. An - entry with a value of 0.0.0.0 is considered a - default route. Multiple routes to a single - destination can appear in the table, but access to - such multiple entries is dependent on the table- - access mechanisms defined by the network - management protocol in use." - ::= { ipRouteEntry 1 } - - ipRouteIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The index value which uniquely identifies the - local interface through which the next hop of this - route should be reached. The interface identified - by a particular value of this index is the same - interface as identified by the same value of - ifIndex." - ::= { ipRouteEntry 2 } - - ipRouteMetric1 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The primary routing metric for this route. The - semantics of this metric are determined by the - routing-protocol specified in the route's - ipRouteProto value. If this metric is not used, - its value should be set to -1." - ::= { ipRouteEntry 3 } - - ipRouteMetric2 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - - - -SNMP Working Group [Page 34] - -RFC 1213 MIB-II March 1991 - - - "An alternate routing metric for this route. The - semantics of this metric are determined by the - routing-protocol specified in the route's - ipRouteProto value. If this metric is not used, - its value should be set to -1." - ::= { ipRouteEntry 4 } - - ipRouteMetric3 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "An alternate routing metric for this route. The - semantics of this metric are determined by the - routing-protocol specified in the route's - ipRouteProto value. If this metric is not used, - its value should be set to -1." - ::= { ipRouteEntry 5 } - - ipRouteMetric4 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "An alternate routing metric for this route. The - semantics of this metric are determined by the - routing-protocol specified in the route's - ipRouteProto value. If this metric is not used, - its value should be set to -1." - ::= { ipRouteEntry 6 } - - ipRouteNextHop OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The IP address of the next hop of this route. - (In the case of a route bound to an interface - which is realized via a broadcast media, the value - of this field is the agent's IP address on that - interface.)" - ::= { ipRouteEntry 7 } - - ipRouteType OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - - invalid(2), -- an invalidated route - - - -SNMP Working Group [Page 35] - -RFC 1213 MIB-II March 1991 - - - -- route to directly - direct(3), -- connected (sub-)network - - -- route to a non-local - indirect(4) -- host/network/sub-network - } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The type of route. Note that the values - direct(3) and indirect(4) refer to the notion of - direct and indirect routing in the IP - architecture. - - Setting this object to the value invalid(2) has - the effect of invalidating the corresponding entry - in the ipRouteTable object. That is, it - effectively dissasociates the destination - identified with said entry from the route - identified with said entry. It is an - implementation-specific matter as to whether the - agent removes an invalidated entry from the table. - Accordingly, management stations must be prepared - to receive tabular information from agents that - corresponds to entries not currently in use. - Proper interpretation of such entries requires - examination of the relevant ipRouteType object." - ::= { ipRouteEntry 8 } - - ipRouteProto OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - - -- non-protocol information, - -- e.g., manually configured - local(2), -- entries - - -- set via a network - netmgmt(3), -- management protocol - - -- obtained via ICMP, - icmp(4), -- e.g., Redirect - - -- the remaining values are - -- all gateway routing - -- protocols - egp(5), - ggp(6), - - - -SNMP Working Group [Page 36] - -RFC 1213 MIB-II March 1991 - - - hello(7), - rip(8), - is-is(9), - es-is(10), - ciscoIgrp(11), - bbnSpfIgp(12), - ospf(13), - bgp(14) - } - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The routing mechanism via which this route was - learned. Inclusion of values for gateway routing - protocols is not intended to imply that hosts - should support those protocols." - ::= { ipRouteEntry 9 } - - ipRouteAge OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The number of seconds since this route was last - updated or otherwise determined to be correct. - Note that no semantics of `too old' can be implied - except through knowledge of the routing protocol - by which the route was learned." - ::= { ipRouteEntry 10 } - - ipRouteMask OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-write - STATUS mandatory - DESCRIPTION - "Indicate the mask to be logical-ANDed with the - destination address before being compared to the - value in the ipRouteDest field. For those systems - that do not support arbitrary subnet masks, an - agent constructs the value of the ipRouteMask by - determining whether the value of the correspondent - ipRouteDest field belong to a class-A, B, or C - network, and then using one of: - - mask network - 255.0.0.0 class-A - 255.255.0.0 class-B - 255.255.255.0 class-C - - - -SNMP Working Group [Page 37] - -RFC 1213 MIB-II March 1991 - - - If the value of the ipRouteDest is 0.0.0.0 (a - default route), then the mask value is also - 0.0.0.0. It should be noted that all IP routing - subsystems implicitly use this mechanism." - ::= { ipRouteEntry 11 } - - ipRouteMetric5 OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "An alternate routing metric for this route. The - semantics of this metric are determined by the - routing-protocol specified in the route's - ipRouteProto value. If this metric is not used, - its value should be set to -1." - ::= { ipRouteEntry 12 } - - ipRouteInfo OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "A reference to MIB definitions specific to the - particular routing protocol which is responsible - for this route, as determined by the value - specified in the route's ipRouteProto value. If - this information is not present, its value should - be set to the OBJECT IDENTIFIER { 0 0 }, which is - a syntatically valid object identifier, and any - conformant implementation of ASN.1 and BER must be - able to generate and recognize this value." - ::= { ipRouteEntry 13 } - - - -- the IP Address Translation table - - -- The IP address translation table contain the IpAddress to - -- `physical' address equivalences. Some interfaces do not - -- use translation tables for determining address - -- equivalences (e.g., DDN-X.25 has an algorithmic method); - -- if all interfaces are of this type, then the Address - -- Translation table is empty, i.e., has zero entries. - - ipNetToMediaTable OBJECT-TYPE - SYNTAX SEQUENCE OF IpNetToMediaEntry - ACCESS not-accessible - STATUS mandatory - - - -SNMP Working Group [Page 38] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "The IP Address Translation table used for mapping - from IP addresses to physical addresses." - ::= { ip 22 } - - ipNetToMediaEntry OBJECT-TYPE - SYNTAX IpNetToMediaEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "Each entry contains one IpAddress to `physical' - address equivalence." - INDEX { ipNetToMediaIfIndex, - ipNetToMediaNetAddress } - ::= { ipNetToMediaTable 1 } - - IpNetToMediaEntry ::= - SEQUENCE { - ipNetToMediaIfIndex - INTEGER, - ipNetToMediaPhysAddress - PhysAddress, - ipNetToMediaNetAddress - IpAddress, - ipNetToMediaType - INTEGER - } - - ipNetToMediaIfIndex OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The interface on which this entry's equivalence - is effective. The interface identified by a - particular value of this index is the same - interface as identified by the same value of - ifIndex." - ::= { ipNetToMediaEntry 1 } - - ipNetToMediaPhysAddress OBJECT-TYPE - SYNTAX PhysAddress - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The media-dependent `physical' address." - ::= { ipNetToMediaEntry 2 } - - - - -SNMP Working Group [Page 39] - -RFC 1213 MIB-II March 1991 - - - ipNetToMediaNetAddress OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The IpAddress corresponding to the media- - dependent `physical' address." - ::= { ipNetToMediaEntry 3 } - - ipNetToMediaType OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - invalid(2), -- an invalidated mapping - dynamic(3), - static(4) - } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The type of mapping. - - Setting this object to the value invalid(2) has - the effect of invalidating the corresponding entry - in the ipNetToMediaTable. That is, it effectively - dissasociates the interface identified with said - entry from the mapping identified with said entry. - It is an implementation-specific matter as to - whether the agent removes an invalidated entry - from the table. Accordingly, management stations - must be prepared to receive tabular information - from agents that corresponds to entries not - currently in use. Proper interpretation of such - entries requires examination of the relevant - ipNetToMediaType object." - ::= { ipNetToMediaEntry 4 } - - - -- additional IP objects - - ipRoutingDiscards OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of routing entries which were chosen - to be discarded even though they are valid. One - possible reason for discarding such an entry could - be to free-up buffer space for other routing - - - -SNMP Working Group [Page 40] - -RFC 1213 MIB-II March 1991 - - - entries." - ::= { ip 23 } - - - -- the ICMP group - - -- Implementation of the ICMP group is mandatory for all - -- systems. - - icmpInMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of ICMP messages which the - entity received. Note that this counter includes - all those counted by icmpInErrors." - ::= { icmp 1 } - - icmpInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP messages which the entity - received but determined as having ICMP-specific - errors (bad ICMP checksums, bad length, etc.)." - ::= { icmp 2 } - - icmpInDestUnreachs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Destination Unreachable - messages received." - ::= { icmp 3 } - - icmpInTimeExcds OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Time Exceeded messages - received." - ::= { icmp 4 } - - - - - -SNMP Working Group [Page 41] - -RFC 1213 MIB-II March 1991 - - - icmpInParmProbs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Parameter Problem messages - received." - ::= { icmp 5 } - - icmpInSrcQuenchs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Source Quench messages - received." - ::= { icmp 6 } - - icmpInRedirects OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Redirect messages received." - ::= { icmp 7 } - - icmpInEchos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Echo (request) messages - received." - ::= { icmp 8 } - - icmpInEchoReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Echo Reply messages received." - ::= { icmp 9 } - - icmpInTimestamps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - - - -SNMP Working Group [Page 42] - -RFC 1213 MIB-II March 1991 - - - "The number of ICMP Timestamp (request) messages - received." - ::= { icmp 10 } - - icmpInTimestampReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Timestamp Reply messages - received." - ::= { icmp 11 } - - icmpInAddrMasks OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Address Mask Request messages - received." - ::= { icmp 12 } - - icmpInAddrMaskReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Address Mask Reply messages - received." - ::= { icmp 13 } - - icmpOutMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of ICMP messages which this - entity attempted to send. Note that this counter - includes all those counted by icmpOutErrors." - ::= { icmp 14 } - - icmpOutErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP messages which this entity did - not send due to problems discovered within ICMP - - - -SNMP Working Group [Page 43] - -RFC 1213 MIB-II March 1991 - - - such as a lack of buffers. This value should not - include errors discovered outside the ICMP layer - such as the inability of IP to route the resultant - datagram. In some implementations there may be no - types of error which contribute to this counter's - value." - ::= { icmp 15 } - - icmpOutDestUnreachs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Destination Unreachable - messages sent." - ::= { icmp 16 } - - icmpOutTimeExcds OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Time Exceeded messages sent." - ::= { icmp 17 } - - icmpOutParmProbs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Parameter Problem messages - sent." - ::= { icmp 18 } - - icmpOutSrcQuenchs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Source Quench messages sent." - ::= { icmp 19 } - - icmpOutRedirects OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Redirect messages sent. For a - - - -SNMP Working Group [Page 44] - -RFC 1213 MIB-II March 1991 - - - host, this object will always be zero, since hosts - do not send redirects." - ::= { icmp 20 } - - icmpOutEchos OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Echo (request) messages sent." - ::= { icmp 21 } - - icmpOutEchoReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Echo Reply messages sent." - ::= { icmp 22 } - - icmpOutTimestamps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Timestamp (request) messages - sent." - ::= { icmp 23 } - - icmpOutTimestampReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Timestamp Reply messages - sent." - ::= { icmp 24 } - - icmpOutAddrMasks OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Address Mask Request messages - sent." - ::= { icmp 25 } - - - - - -SNMP Working Group [Page 45] - -RFC 1213 MIB-II March 1991 - - - icmpOutAddrMaskReps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of ICMP Address Mask Reply messages - sent." - ::= { icmp 26 } - - - -- the TCP group - - -- Implementation of the TCP group is mandatory for all - -- systems that implement the TCP. - - -- Note that instances of object types that represent - -- information about a particular TCP connection are - -- transient; they persist only as long as the connection - -- in question. - - tcpRtoAlgorithm OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - - constant(2), -- a constant rto - rsre(3), -- MIL-STD-1778, Appendix B - vanj(4) -- Van Jacobson's algorithm [10] - } - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The algorithm used to determine the timeout value - used for retransmitting unacknowledged octets." - ::= { tcp 1 } - - tcpRtoMin OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The minimum value permitted by a TCP - implementation for the retransmission timeout, - measured in milliseconds. More refined semantics - for objects of this type depend upon the algorithm - used to determine the retransmission timeout. In - particular, when the timeout algorithm is rsre(3), - an object of this type has the semantics of the - LBOUND quantity described in RFC 793." - - - -SNMP Working Group [Page 46] - -RFC 1213 MIB-II March 1991 - - - ::= { tcp 2 } - - - tcpRtoMax OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The maximum value permitted by a TCP - implementation for the retransmission timeout, - measured in milliseconds. More refined semantics - for objects of this type depend upon the algorithm - used to determine the retransmission timeout. In - particular, when the timeout algorithm is rsre(3), - an object of this type has the semantics of the - UBOUND quantity described in RFC 793." - ::= { tcp 3 } - - tcpMaxConn OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The limit on the total number of TCP connections - the entity can support. In entities where the - maximum number of connections is dynamic, this - object should contain the value -1." - ::= { tcp 4 } - - tcpActiveOpens OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of times TCP connections have made a - direct transition to the SYN-SENT state from the - CLOSED state." - ::= { tcp 5 } - - tcpPassiveOpens OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of times TCP connections have made a - direct transition to the SYN-RCVD state from the - LISTEN state." - ::= { tcp 6 } - - - -SNMP Working Group [Page 47] - -RFC 1213 MIB-II March 1991 - - - tcpAttemptFails OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of times TCP connections have made a - direct transition to the CLOSED state from either - the SYN-SENT state or the SYN-RCVD state, plus the - number of times TCP connections have made a direct - transition to the LISTEN state from the SYN-RCVD - state." - ::= { tcp 7 } - - tcpEstabResets OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of times TCP connections have made a - direct transition to the CLOSED state from either - the ESTABLISHED state or the CLOSE-WAIT state." - ::= { tcp 8 } - - tcpCurrEstab OBJECT-TYPE - SYNTAX Gauge - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of TCP connections for which the - current state is either ESTABLISHED or CLOSE- - WAIT." - ::= { tcp 9 } - - tcpInSegs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of segments received, including - those received in error. This count includes - segments received on currently established - connections." - ::= { tcp 10 } - - tcpOutSegs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 48] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "The total number of segments sent, including - those on current connections but excluding those - containing only retransmitted octets." - ::= { tcp 11 } - - tcpRetransSegs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of segments retransmitted - that - is, the number of TCP segments transmitted - containing one or more previously transmitted - octets." - ::= { tcp 12 } - - - -- the TCP Connection table - - -- The TCP connection table contains information about this - -- entity's existing TCP connections. - - tcpConnTable OBJECT-TYPE - SYNTAX SEQUENCE OF TcpConnEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "A table containing TCP connection-specific - information." - ::= { tcp 13 } - - tcpConnEntry OBJECT-TYPE - SYNTAX TcpConnEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "Information about a particular current TCP - connection. An object of this type is transient, - in that it ceases to exist when (or soon after) - the connection makes the transition to the CLOSED - state." - INDEX { tcpConnLocalAddress, - tcpConnLocalPort, - tcpConnRemAddress, - tcpConnRemPort } - ::= { tcpConnTable 1 } - - - - -SNMP Working Group [Page 49] - -RFC 1213 MIB-II March 1991 - - - TcpConnEntry ::= - SEQUENCE { - tcpConnState - INTEGER, - tcpConnLocalAddress - IpAddress, - tcpConnLocalPort - INTEGER (0..65535), - tcpConnRemAddress - IpAddress, - tcpConnRemPort - INTEGER (0..65535) - } - - tcpConnState OBJECT-TYPE - SYNTAX INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11), - deleteTCB(12) - } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "The state of this TCP connection. - - The only value which may be set by a management - station is deleteTCB(12). Accordingly, it is - appropriate for an agent to return a `badValue' - response if a management station attempts to set - this object to any other value. - - If a management station sets this object to the - value deleteTCB(12), then this has the effect of - deleting the TCB (as defined in RFC 793) of the - corresponding connection on the managed node, - resulting in immediate termination of the - connection. - - As an implementation-specific option, a RST - - - -SNMP Working Group [Page 50] - -RFC 1213 MIB-II March 1991 - - - segment may be sent from the managed node to the - other TCP endpoint (note however that RST segments - are not sent reliably)." - ::= { tcpConnEntry 1 } - - tcpConnLocalAddress OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The local IP address for this TCP connection. In - the case of a connection in the listen state which - is willing to accept connections for any IP - interface associated with the node, the value - 0.0.0.0 is used." - ::= { tcpConnEntry 2 } - - tcpConnLocalPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The local port number for this TCP connection." - ::= { tcpConnEntry 3 } - - tcpConnRemAddress OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The remote IP address for this TCP connection." - ::= { tcpConnEntry 4 } - - tcpConnRemPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The remote port number for this TCP connection." - ::= { tcpConnEntry 5 } - - - -- additional TCP objects - - tcpInErrs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 51] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "The total number of segments received in error - (e.g., bad TCP checksums)." - ::= { tcp 14 } - - tcpOutRsts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of TCP segments sent containing the - RST flag." - ::= { tcp 15 } - - - -- the UDP group - - -- Implementation of the UDP group is mandatory for all - -- systems which implement the UDP. - - udpInDatagrams OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of UDP datagrams delivered to - UDP users." - ::= { udp 1 } - - udpNoPorts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of received UDP datagrams for - which there was no application at the destination - port." - ::= { udp 2 } - - udpInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of received UDP datagrams that could - not be delivered for reasons other than the lack - of an application at the destination port." - ::= { udp 3 } - - - -SNMP Working Group [Page 52] - -RFC 1213 MIB-II March 1991 - - - udpOutDatagrams OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of UDP datagrams sent from this - entity." - ::= { udp 4 } - - - -- the UDP Listener table - - -- The UDP listener table contains information about this - -- entity's UDP end-points on which a local application is - -- currently accepting datagrams. - - udpTable OBJECT-TYPE - SYNTAX SEQUENCE OF UdpEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "A table containing UDP listener information." - ::= { udp 5 } - - udpEntry OBJECT-TYPE - SYNTAX UdpEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "Information about a particular current UDP - listener." - INDEX { udpLocalAddress, udpLocalPort } - ::= { udpTable 1 } - - UdpEntry ::= - SEQUENCE { - udpLocalAddress - IpAddress, - udpLocalPort - INTEGER (0..65535) - } - - udpLocalAddress OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The local IP address for this UDP listener. In - - - -SNMP Working Group [Page 53] - -RFC 1213 MIB-II March 1991 - - - the case of a UDP listener which is willing to - accept datagrams for any IP interface associated - with the node, the value 0.0.0.0 is used." - ::= { udpEntry 1 } - - udpLocalPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The local port number for this UDP listener." - ::= { udpEntry 2 } - - - -- the EGP group - - -- Implementation of the EGP group is mandatory for all - -- systems which implement the EGP. - - egpInMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP messages received without - error." - ::= { egp 1 } - - egpInErrors OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP messages received that proved - to be in error." - ::= { egp 2 } - - egpOutMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of locally generated EGP - messages." - ::= { egp 3 } - - egpOutErrors OBJECT-TYPE - SYNTAX Counter - - - -SNMP Working Group [Page 54] - -RFC 1213 MIB-II March 1991 - - - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of locally generated EGP messages not - sent due to resource limitations within an EGP - entity." - ::= { egp 4 } - - - -- the EGP Neighbor table - - -- The EGP neighbor table contains information about this - -- entity's EGP neighbors. - - egpNeighTable OBJECT-TYPE - SYNTAX SEQUENCE OF EgpNeighEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "The EGP neighbor table." - ::= { egp 5 } - - egpNeighEntry OBJECT-TYPE - SYNTAX EgpNeighEntry - ACCESS not-accessible - STATUS mandatory - DESCRIPTION - "Information about this entity's relationship with - a particular EGP neighbor." - INDEX { egpNeighAddr } - ::= { egpNeighTable 1 } - - EgpNeighEntry ::= - SEQUENCE { - egpNeighState - INTEGER, - egpNeighAddr - IpAddress, - egpNeighAs - INTEGER, - egpNeighInMsgs - Counter, - egpNeighInErrs - Counter, - egpNeighOutMsgs - Counter, - egpNeighOutErrs - Counter, - - - -SNMP Working Group [Page 55] - -RFC 1213 MIB-II March 1991 - - - egpNeighInErrMsgs - Counter, - egpNeighOutErrMsgs - Counter, - egpNeighStateUps - Counter, - egpNeighStateDowns - Counter, - egpNeighIntervalHello - INTEGER, - egpNeighIntervalPoll - INTEGER, - egpNeighMode - INTEGER, - egpNeighEventTrigger - INTEGER - } - - egpNeighState OBJECT-TYPE - SYNTAX INTEGER { - idle(1), - acquisition(2), - down(3), - up(4), - cease(5) - } - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The EGP state of the local system with respect to - this entry's EGP neighbor. Each EGP state is - represented by a value that is one greater than - the numerical value associated with said state in - RFC 904." - ::= { egpNeighEntry 1 } - - egpNeighAddr OBJECT-TYPE - SYNTAX IpAddress - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The IP address of this entry's EGP neighbor." - ::= { egpNeighEntry 2 } - - egpNeighAs OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 56] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "The autonomous system of this EGP peer. Zero - should be specified if the autonomous system - number of the neighbor is not yet known." - ::= { egpNeighEntry 3 } - - egpNeighInMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP messages received without error - from this EGP peer." - ::= { egpNeighEntry 4 } - - egpNeighInErrs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP messages received from this EGP - peer that proved to be in error (e.g., bad EGP - checksum)." - ::= { egpNeighEntry 5 } - - egpNeighOutMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of locally generated EGP messages to - this EGP peer." - ::= { egpNeighEntry 6 } - - egpNeighOutErrs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of locally generated EGP messages not - sent to this EGP peer due to resource limitations - within an EGP entity." - ::= { egpNeighEntry 7 } - - egpNeighInErrMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 57] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "The number of EGP-defined error messages received - from this EGP peer." - ::= { egpNeighEntry 8 } - - egpNeighOutErrMsgs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP-defined error messages sent to - this EGP peer." - ::= { egpNeighEntry 9 } - - egpNeighStateUps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP state transitions to the UP - state with this EGP peer." - ::= { egpNeighEntry 10 } - - egpNeighStateDowns OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The number of EGP state transitions from the UP - state to any other state with this EGP peer." - ::= { egpNeighEntry 11 } - - egpNeighIntervalHello OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The interval between EGP Hello command - retransmissions (in hundredths of a second). This - represents the t1 timer as defined in RFC 904." - ::= { egpNeighEntry 12 } - - egpNeighIntervalPoll OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The interval between EGP poll command - - - -SNMP Working Group [Page 58] - -RFC 1213 MIB-II March 1991 - - - retransmissions (in hundredths of a second). This - represents the t3 timer as defined in RFC 904." - ::= { egpNeighEntry 13 } - - egpNeighMode OBJECT-TYPE - SYNTAX INTEGER { active(1), passive(2) } - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The polling mode of this EGP entity, either - passive or active." - ::= { egpNeighEntry 14 } - - egpNeighEventTrigger OBJECT-TYPE - SYNTAX INTEGER { start(1), stop(2) } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "A control variable used to trigger operator- - initiated Start and Stop events. When read, this - variable always returns the most recent value that - egpNeighEventTrigger was set to. If it has not - been set since the last initialization of the - network management subsystem on the node, it - returns a value of `stop'. - - When set, this variable causes a Start or Stop - event on the specified neighbor, as specified on - pages 8-10 of RFC 904. Briefly, a Start event - causes an Idle peer to begin neighbor acquisition - and a non-Idle peer to reinitiate neighbor - acquisition. A stop event causes a non-Idle peer - to return to the Idle state until a Start event - occurs, either via egpNeighEventTrigger or - otherwise." - ::= { egpNeighEntry 15 } - - - -- additional EGP objects - - egpAs OBJECT-TYPE - SYNTAX INTEGER - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The autonomous system number of this EGP entity." - ::= { egp 6 } - - - - -SNMP Working Group [Page 59] - -RFC 1213 MIB-II March 1991 - - - -- the Transmission group - - -- Based on the transmission media underlying each interface - -- on a system, the corresponding portion of the Transmission - -- group is mandatory for that system. - - -- When Internet-standard definitions for managing - -- transmission media are defined, the transmission group is - -- used to provide a prefix for the names of those objects. - - -- Typically, such definitions reside in the experimental - -- portion of the MIB until they are "proven", then as a - -- part of the Internet standardization process, the - -- definitions are accordingly elevated and a new object - -- identifier, under the transmission group is defined. By - -- convention, the name assigned is: - -- - -- type OBJECT IDENTIFIER ::= { transmission number } - -- - -- where "type" is the symbolic value used for the media in - -- the ifType column of the ifTable object, and "number" is - -- the actual integer value corresponding to the symbol. - - - -- the SNMP group - - -- Implementation of the SNMP group is mandatory for all - -- systems which support an SNMP protocol entity. Some of - -- the objects defined below will be zero-valued in those - -- SNMP implementations that are optimized to support only - -- those functions specific to either a management agent or - -- a management station. In particular, it should be - -- observed that the objects below refer to an SNMP entity, - -- and there may be several SNMP entities residing on a - -- managed node (e.g., if the node is hosting acting as - -- a management station). - - snmpInPkts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of Messages delivered to the - SNMP entity from the transport service." - ::= { snmp 1 } - - snmpOutPkts OBJECT-TYPE - SYNTAX Counter - - - -SNMP Working Group [Page 60] - -RFC 1213 MIB-II March 1991 - - - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Messages which were - passed from the SNMP protocol entity to the - transport service." - ::= { snmp 2 } - - snmpInBadVersions OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Messages which were - delivered to the SNMP protocol entity and were for - an unsupported SNMP version." - ::= { snmp 3 } - - snmpInBadCommunityNames OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Messages delivered to - the SNMP protocol entity which used a SNMP - community name not known to said entity." - ::= { snmp 4 } - - snmpInBadCommunityUses OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Messages delivered to - the SNMP protocol entity which represented an SNMP - operation which was not allowed by the SNMP - community named in the Message." - ::= { snmp 5 } - - snmpInASNParseErrs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of ASN.1 or BER errors - encountered by the SNMP protocol entity when - decoding received SNMP Messages." - ::= { snmp 6 } - - - -SNMP Working Group [Page 61] - -RFC 1213 MIB-II March 1991 - - - -- { snmp 7 } is not used - - snmpInTooBigs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - delivered to the SNMP protocol entity and for - which the value of the error-status field is - `tooBig'." - ::= { snmp 8 } - - snmpInNoSuchNames OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - delivered to the SNMP protocol entity and for - which the value of the error-status field is - `noSuchName'." - ::= { snmp 9 } - - snmpInBadValues OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - delivered to the SNMP protocol entity and for - which the value of the error-status field is - `badValue'." - ::= { snmp 10 } - - snmpInReadOnlys OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number valid SNMP PDUs which were - delivered to the SNMP protocol entity and for - which the value of the error-status field is - `readOnly'. It should be noted that it is a - protocol error to generate an SNMP PDU which - contains the value `readOnly' in the error-status - field, as such this object is provided as a means - of detecting incorrect implementations of the - - - -SNMP Working Group [Page 62] - -RFC 1213 MIB-II March 1991 - - - SNMP." - ::= { snmp 11 } - - snmpInGenErrs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - delivered to the SNMP protocol entity and for - which the value of the error-status field is - `genErr'." - ::= { snmp 12 } - - snmpInTotalReqVars OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of MIB objects which have been - retrieved successfully by the SNMP protocol entity - as the result of receiving valid SNMP Get-Request - and Get-Next PDUs." - ::= { snmp 13 } - - snmpInTotalSetVars OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of MIB objects which have been - altered successfully by the SNMP protocol entity - as the result of receiving valid SNMP Set-Request - PDUs." - ::= { snmp 14 } - - snmpInGetRequests OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Get-Request PDUs which - have been accepted and processed by the SNMP - protocol entity." - ::= { snmp 15 } - - snmpInGetNexts OBJECT-TYPE - SYNTAX Counter - - - -SNMP Working Group [Page 63] - -RFC 1213 MIB-II March 1991 - - - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Get-Next PDUs which have - been accepted and processed by the SNMP protocol - entity." - ::= { snmp 16 } - - snmpInSetRequests OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Set-Request PDUs which - have been accepted and processed by the SNMP - protocol entity." - ::= { snmp 17 } - - snmpInGetResponses OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Get-Response PDUs which - have been accepted and processed by the SNMP - protocol entity." - ::= { snmp 18 } - - snmpInTraps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Trap PDUs which have - been accepted and processed by the SNMP protocol - entity." - ::= { snmp 19 } - - snmpOutTooBigs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - generated by the SNMP protocol entity and for - which the value of the error-status field is - `tooBig.'" - ::= { snmp 20 } - - - -SNMP Working Group [Page 64] - -RFC 1213 MIB-II March 1991 - - - snmpOutNoSuchNames OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - generated by the SNMP protocol entity and for - which the value of the error-status is - `noSuchName'." - ::= { snmp 21 } - - snmpOutBadValues OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - generated by the SNMP protocol entity and for - which the value of the error-status field is - `badValue'." - ::= { snmp 22 } - - -- { snmp 23 } is not used - - snmpOutGenErrs OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP PDUs which were - generated by the SNMP protocol entity and for - which the value of the error-status field is - `genErr'." - ::= { snmp 24 } - - snmpOutGetRequests OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Get-Request PDUs which - have been generated by the SNMP protocol entity." - ::= { snmp 25 } - - snmpOutGetNexts OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - - - -SNMP Working Group [Page 65] - -RFC 1213 MIB-II March 1991 - - - DESCRIPTION - "The total number of SNMP Get-Next PDUs which have - been generated by the SNMP protocol entity." - ::= { snmp 26 } - - snmpOutSetRequests OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Set-Request PDUs which - have been generated by the SNMP protocol entity." - ::= { snmp 27 } - - snmpOutGetResponses OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Get-Response PDUs which - have been generated by the SNMP protocol entity." - ::= { snmp 28 } - - snmpOutTraps OBJECT-TYPE - SYNTAX Counter - ACCESS read-only - STATUS mandatory - DESCRIPTION - "The total number of SNMP Trap PDUs which have - been generated by the SNMP protocol entity." - ::= { snmp 29 } - - snmpEnableAuthenTraps OBJECT-TYPE - SYNTAX INTEGER { enabled(1), disabled(2) } - ACCESS read-write - STATUS mandatory - DESCRIPTION - "Indicates whether the SNMP agent process is - permitted to generate authentication-failure - traps. The value of this object overrides any - configuration information; as such, it provides a - means whereby all authentication-failure traps may - be disabled. - - Note that it is strongly recommended that this - object be stored in non-volatile memory so that it - remains constant between re-initializations of the - network management system." - - - -SNMP Working Group [Page 66] - -RFC 1213 MIB-II March 1991 - - - ::= { snmp 30 } - - END - -7. Acknowledgements - - This document was produced by the SNMP Working Group: - - Anne Ambler, Spider - Karl Auerbach, Sun - Fred Baker, ACC - David Bridgham, Epilogue Technology - Ken Brinkerhoff - Ron Broersma, NOSC - Brian Brown, Synoptics - Jack Brown, US Army - Theodore Brunner, Bellcore - Jeff Buffum, HP - Jeffrey Buffum, HP - John Burress, Wellfleet - Jeffrey D. Case, University of Tennessee at Knoxville - Chris Chiptasso, Spartacus - Paul Ciarfella, DEC - Bob Collet - John Cook, Chipcom - Tracy Cox, Bellcore - James R. Davin, MIT-LCS - Eric Decker, cisco - Kurt Dobbins, Cabletron - Nadya El-Afandi, Network Systems - Gary Ellis, HP - Fred Engle - Mike Erlinger - Mark S. Fedor, PSI - Richard Fox, Synoptics - Karen Frisa, CMU - Stan Froyd, ACC - Chris Gunner, DEC - Fred Harris, University of Tennessee at Knoxville - Ken Hibbard, Xylogics - Ole Jacobsen, Interop - Ken Jones - Satish Joshi, Synoptics - Frank Kastenholz, Racal-Interlan - Shimshon Kaufman, Spartacus - Ken Key, University of Tennessee at Knoxville - Jim Kinder, Fibercom - Alex Koifman, BBN - - - -SNMP Working Group [Page 67] - -RFC 1213 MIB-II March 1991 - - - Christopher Kolb, PSI - Cheryl Krupczak, NCR - Paul Langille, DEC - Martin Lee Schoffstall, PSI - Peter Lin, Vitalink - John Lunny, TWG - Carl Malamud - Gary Malkin, FTP Software, Inc. - Randy Mayhew, University of Tennessee at Knoxville - Keith McCloghrie, Hughes LAN Systems - Donna McMaster, David Systems - Lynn Monsanto, Sun - Dave Perkins, 3COM - Jim Reinstedler, Ungerman Bass - Anil Rijsinghani, DEC - Kathy Rinehart, Arnold AFB - Kary Robertson - Marshall T. Rose, PSI (chair) - L. Michael Sabo, NCSC - Jon Saperia, DEC - Greg Satz, cisco - Martin Schoffstall, PSI - John Seligson - Steve Sherry, Xyplex - Fei Shu, NEC - Sam Sjogren, TGV - Mark Sleeper, Sparta - Lance Sprung - Mike St.Johns - Bob Stewart, Xyplex - Emil Sturniold - Kaj Tesink, Bellcore - Geoff Thompson, Synoptics - Dean Throop, Data General - Bill Townsend, Xylogics - Maurice Turcotte, Racal-Milgo - Kannan Varadhou - Sudhanshu Verma, HP - Bill Versteeg, Network Research Corporation - Warren Vik, Interactive Systems - David Waitzman, BBN - Steve Waldbusser, CMU - Dan Wintringhan - David Wood - Wengyik Yeong, PSI - Jeff Young, Cray Research - - - - - -SNMP Working Group [Page 68] - -RFC 1213 MIB-II March 1991 - - - In addition, the comments of the following individuals are also - acknolwedged: - - Craig A. Finseth, Minnesota Supercomputer Center, Inc. - Jeffrey C. Honig, Cornell University Theory Center - Philip R. Karn, Bellcore - -8. References - - [1] Cerf, V., "IAB Recommendations for the Development of Internet - Network Management Standards", RFC 1052, NRI, April 1988. - - [2] Rose M., and K. McCloghrie, "Structure and Identification of - Management Information for TCP/IP-based internets," RFC 1065, - TWG, August 1988. - - [3] McCloghrie, K., and M. Rose, "Management Information Base for - Network Management of TCP/IP-based internets, RFC 1066, TWG, - August 1988. - - [4] Cerf, V., "Report of the Second Ad Hoc Network Management Review - Group", RFC 1109, NRI, August 1989. - - [5] Case, J., Fedor, M., Schoffstall, M., and J. Davin, "Simple - Network Management Protocol (SNMP)", RFC 1098, University of - Tennessee at Knoxville, NYSERNet, Inc., Rensselaer Polytechnic - Institute, MIT Laboratory for Computer Science, April 1989. - - [6] Postel, J., and J. Reynolds, "TELNET Protocol Specification", RFC - 854, USC/Information Sciences Institute, May 1983. - - [7] Satz, G., "Connectionless Network Protocol (ISO 8473) and End - System to Intermediate System (ISO 9542) Management Information - Base", RFC 1162, cisco Systems, Inc., June 1990. - - [8] Information processing systems - Open Systems Interconnection - - Specification of Abstract Syntax Notation One (ASN.1), - International Organization for Standardization, International - Standard 8824, December 1987. - - [9] Information processing systems - Open Systems Interconnection - - Specification of Basic Encoding Rules for Abstract Notation One - (ASN.1), International Organization for Standardization, - International Standard 8825, December 1987. - - [10] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM 1988, - Stanford, California. - - - - -SNMP Working Group [Page 69] - -RFC 1213 MIB-II March 1991 - - - [11] Hagens, R., Hall, N., and M. Rose, "Use of the Internet as a - Subnetwork for Experimentation with the OSI Network Layer", RFC - 1070, U of Wiscsonsin - Madison, U of Wiscsonsin - Madison, The - Wollongong Group, February 1989. - - [12] Rose M., and K. McCloghrie, "Structure and Identification of - Management Information for TCP/IP-based internets", RFC 1155, - Performance Systems International, Hughes LAN Systems, May 1990. - - [13] Case, J., Fedor, M., Schoffstall, M., and J. Davin, "Simple - Network Management Protocol", RFC 1157, SNMP Research, - Performance Systems International, Performance Systems - International, MIT Laboratory for Computer Science, May 1990. - - [14] Rose, M., and K. McCloghrie, Editors, "Concise MIB Definitions", - RFC 1212, Performance Systems International, Hughes LAN Systems, - March 1991. - -9. Security Considerations - - Security issues are not discussed in this memo. - -10. Authors' Addresses - - Keith McCloghrie - Hughes LAN Systems - 1225 Charleston Road - Mountain View, CA 94043 - 1225 Charleston Road - Mountain View, CA 94043 - - Phone: (415) 966-7934 - - EMail: kzm@hls.com - - - Marshall T. Rose - Performance Systems International - 5201 Great America Parkway - Suite 3106 - Santa Clara, CA 95054 - - Phone: +1 408 562 6222 - - EMail: mrose@psi.com - X.500: rose, psi, us - - - - - -SNMP Working Group [Page 70] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1263.txt b/ext/picotcp/RFC/rfc1263.txt deleted file mode 100644 index 55b6e39..0000000 --- a/ext/picotcp/RFC/rfc1263.txt +++ /dev/null @@ -1,1067 +0,0 @@ - - - - - - -Network Working Group S. O'Malley -Request for Comments: 1263 L. Peterson - University of Arizona - October 1991 - - - TCP EXTENSIONS CONSIDERED HARMFUL - - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard. Distribution of this document is - unlimited. - -Abstract - - This RFC comments on recent proposals to extend TCP. It argues that - the backward compatible extensions proposed in RFC's 1072 and 1185 - should not be pursued, and proposes an alternative way to evolve the - Internet protocol suite. Its purpose is to stimulate discussion in - the Internet community. - -1. Introduction - - The rapid growth of the size, capacity, and complexity of the - Internet has led to the need to change the existing protocol suite. - For example, the maximum TCP window size is no longer sufficient to - efficiently support the high capacity links currently being planned - and constructed. One is then faced with the choice of either leaving - the protocol alone and accepting the fact that TCP will run no faster - on high capacity links than on low capacity links, or changing TCP. - This is not an isolated incident. We have counted at least eight - other proposed changes to TCP (some to be taken more seriously than - others), and the question is not whether to change the protocol - suite, but what is the most cost effective way to change it. - - This RFC compares the costs and benefits of three approaches to - making these changes: the creation of new protocols, backward - compatible protocol extensions, and protocol evolution. The next - section introduces these three approaches and enumerates the - strengths and weaknesses of each. The following section describes - how we believe these three approaches are best applied to the many - proposed changes to TCP. Note that we have not written this RFC as an - academic exercise. It is our intent to argue against acceptance of - the various TCP extensions, most notably RFC's 1072 and 1185 [4,5], - by describing a more palatable alternative. - - - - -O'Malley & Peterson [Page 1] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - -2. Creation vs. Extension vs. Evolution - -2.1. Protocol Creation - - Protocol creation involves the design, implementation, - standardization, and distribution of an entirely new protocol. In - this context, there are two basic reasons for creating a new - protocol. The first is to replace an old protocol that is so outdated - that it can no longer be effectively extended to perform its original - function. The second is to add a new protocol because users are - making demands upon the original protocol that were not envisioned by - the designer and cannot be efficiently handled in terms of the - original protocol. For example, TCP was designed as a reliable - byte-stream protocol but is commonly used as both a reliable record- - stream protocol and a reliable request-reply protocol due to the lack - of such protocols in the Internet protocol suite. The performance - demands placed upon a byte-stream protocol in the new Internet - environment makes it difficult to extend TCP to meet these new - application demands. - - The advantage of creating a new protocol is the ability to start with - a clean sheet of paper when attempting to solve a complex network - problem. The designer, free from the constraints of an existing - protocol, can take maximum advantage of modern network research in - the basic algorithms needed to solve the problem. Even more - importantly, the implementor is free to steal from a large number of - existing academic protocols that have been developed over the years. - In some cases, if truly new functionality is desired, creating a new - protocol is the only viable approach. - - The most obvious disadvantage of this approach is the high cost of - standardizing and distributing an entirely new protocol. Second, - there is the issue of making the new protocol reliable. Since new - protocols have not undergone years of network stress testing, they - often contain bugs which require backward compatible fixes, and - hence, the designer is back where he or she started. A third - disadvantage of introducing new protocols is that they generally have - new interfaces which require significant effort on the part of the - Internet community to use. This alone is often enough to kill a new - protocol. - - Finally, there is a subtle problem introduced by the very freedom - provided by this approach. Specifically, being able to introduce a - new protocol often results in protocols that go far beyond the basic - needs of the situation. New protocols resemble Senate appropriations - bills; they tend to accumulate many amendments that have nothing to - do with the original problem. A good example of this phenomena is the - attempt to standardize VMTP [1] as the Internet RPC protocol. While - - - -O'Malley & Peterson [Page 2] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - VMTP was a large protocol to begin with, the closer it got to - standardization the more features were added until it essentially - collapsed under its own weight. As we argue below, new protocols - should initially be minimal, and then evolve as the situation - dictates. - - -2.2. Backward Compatible Extensions - - In a backward compatible extension, the protocol is modified in such - a fashion that the new version of the protocol can transparently - inter-operate with existing versions of the protocol. This generally - implies no changes to the protocol's header. TCP slow start [3] is an - example of such a change. In a slightly more relaxed version of - backward compatibility, no changes are made to the fixed part of a - protocol's header. Instead, either some fields are added to the - variable length options field found at the end of the header, or - existing header fields are overloaded (i.e., used for multiple - purposes). However, we can find no real advantage to this technique - over simply changing the protocol. - - Backward compatible extensions are widely used to modify protocols - because there is no need to synchronize the distribution of the new - version of the protocol. The new version is essentially allowed to - diffuse through the Internet at its own pace, and at least in theory, - the Internet will continue to function as before. Thus, the explicit - distribution costs are limited. Backward compatible extensions also - avoid the bureaucratic costs of standardizing a new protocol. TCP is - still TCP and the approval cost of a modification to an existing - protocol is much less than that of a new protocol. Finally, the very - difficulty of making such changes tends to restrict the changes to - the minimal set needed to solve the current problem. Thus, it is rare - to see unneeded changes made when using this technique. - - Unfortunately, this approach has several drawbacks. First, the time - to distribute the new version of the protocol to all hosts can be - quite long (forever in fact). This leaves the network in a - heterogeneous state for long periods of time. If there is the - slightest incompatibly between old and new versions, chaos can - result. Thus, the implicit cost of this type of distribution can be - quite high. Second, designing a backward compatible change to a new - protocol is extremely difficult, and the implementations "tend toward - complexity and ugliness" [5]. The need for backward compatibility - ensures that no code can every really be eliminated from the - protocol, and since such vestigial code is rarely executed, it is - often wrong. Finally, most protocols have limits, based upon the - design decisions of it inventors, that simply cannot be side-stepped - in this fashion. - - - -O'Malley & Peterson [Page 3] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - -2.3. Protocol Evolution - - Protocol evolution is an approach to protocol change that attempts to - escape the limits of backward compatibility without incurring all of - the costs of creating new protocols. The basic idea is for the - protocol designer to take an existing protocol that requires - modification and make the desired changes without maintaining - backward compatibility. This drastically simplifies the job of the - protocol designer. For example, the limited TCP window size could be - fixed by changing the definition of the window size in the header - from 16-bits to 32-bits, and re-compiling the protocol. The effect of - backward compatibility would be ensured by simply keeping both the - new and old version of the protocol running until most machines use - the new version. Since the change is small and invisible to the user - interface, it is a trivial problem to dynamically select the correct - TCP version at runtime. How this is done is discussed in the next - section. - - Protocol evolution has several advantages. First, it is by far the - simplest type of modification to make to a protocol, and hence, the - modifications can be made faster and are less likely to contain bugs. - There is no need to worry about the effects of the change on all - previous versions of the protocol. Also, most of the protocol is - carried over into the new version unchanged, thus avoiding the design - and debugging cost of creating an entirely new protocol. Second, - there is no artificial limit to the amount of change that can be made - to a protocol, and as a consequence, its useful lifetime can be - extended indefinitely. In a series of evolutionary steps, it is - possible to make fairly radical changes to a protocol without - upsetting the Internet community greatly. Specifically, it is - possible to both add new features and remove features that are no - longer required for the current environment. Thus, the protocol is - not condemned to grow without bound. Finally, by keeping the old - version of the protocol around, backward compatibility is guaranteed. - The old code will work as well as it ever did. - - Assuming the infrastructure described in the following subsection, - the only real disadvantage of protocol evolution is the amount of - memory required to run several versions of the same protocol. - Fortunately, memory is not the scarcest resource in modern - workstations (it may, however, be at a premium in the BSD kernel and - its derivatives). Since old versions may rarely if ever be executed, - the old versions can be swapped out to disk with little performance - loss. Finally, since this cost is explicit, there is a huge incentive - to eliminate old protocol versions from the network. - - - - - - -O'Malley & Peterson [Page 4] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - -2.4. Infrastructure Support for Protocol Evolution - - The effective use of protocol evolution implies that each protocol is - considered a vector of implementations which share the same top level - interface, and perhaps not much else. TCP[0] is the current - implementation of TCP and exists to provide backward compatibility - with all existing machines. TCP[1] is a version of TCP that is - optimized for high-speed networks. TCP[0] is always present; TCP[1] - may or may not be. Treating TCP as a vector of protocols requires - only three changes to the way protocols are designed and implemented. - - First, each version of TCP is assigned a unique id, but this id is - not given as an IP protocol number. (This is because IP's protocol - number field is only 8 bits long and could easily be exhausted.) The - "obvious" solution to this limitation is to increase IP's protocol - number field to 32 bits. In this case, however, the obvious solution - is wrong, not because of the difficultly of changing IP, but simply - because there is a better approach. The best way to deal with this - problem is to increase the IP protocol number field to 32 bits and - move it to the very end of the IP header (i.e., the first four bytes - of the TCP header). A backward compatible modification would be made - to IP such that for all packets with a special protocol number, say - 77, IP would look into the four bytes following its header for its - de-multiplexing information. On systems which do not support a - modified IP, an actual protocol 77 would be used to perform the de- - multiplexing to the correct TCP version. - - Second, a version control protocol, called VTCP, is used to select - the appropriate version of TCP for a particular connection. VTCP is - an example of a virtual protocol as introduced in [2]. Application - programs access the various versions of TCP through VTCP. When a TCP - connection is opened to a specific machine, VTCP checks its local - cache to determine the highest common version shared by the two - machines. If the target machine is in the cache, it opens that - version of TCP and returns the connection to the protocol above and - does not effect performance. If the target machine is not found in - the cache, VTCP sends a UDP packet to the other machine asking what - versions of TCP that machine supports. If it receives a response, it - uses that information to select a version and puts the information in - the cache. If no reply is forthcoming, it assumes that the other - machine does not support VTCP and attempts to open a TCP[0] - connection. VTCP's cache is flushed occasionally to ensure that its - information is current. - - Note that this is only one possible way for VTCP to decide the right - version of TCP to use. Another possibility is for VTCP to learn the - right version for a particular host when it resolves the host's name. - That is, version information could be stored in the Domain Name - - - -O'Malley & Peterson [Page 5] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - System. It is also possible that VTCP might take the performance - characteristics of the network into consideration when selecting a - version; TCP[0] may in fact turn out to be the correct choice for a - low-bandwidth network. - - Third, because our proposal would lead to a more dynamically changing - network architecture, a mechanism for distributing new versions will - need to be developed. This is clearly the hardest requirement of the - infrastructure, but we believe that it can be addressed in stages. - More importantly, we believe this problem can be addressed after the - decision has been made to go the protocol evolution route. In the - short term, we are considering only a single new version of TCP--- - TCP[1]. This version can be distributed in the same ad hoc way, and - at exactly the same cost, as the backward compatible changes - suggested in RFC's 1072 and 1185. - - In the medium term, we envision the IAB approving new versions of TCP - every year or so. Given this scenario, a simple distribution - mechanism can be designed based on software distribution mechanisms - that have be developed for other environments; e.g., Unix RDIST and - Mach SUP. Such a mechanism need not be available on all hosts. - Instead, hosts will be divided into two sets, those that can quickly - be updated with new protocols and those that cannot. High - performance machines that can use high performance networks will need - the most current version of TCP as soon as it is available, thus they - have incentive to change. Old machines which are too slow to drive a - high capacity lines can be ignored, and probably should be ignored. - - In the long term, we envision protocols being designed on an - application by application basis, without the need for central - approval. In such a world, a common protocol implementation - environment---a protocol backplane---is the right way to go. Given - such a backplane, protocols can be automatically installed over the - network. While we claim to know how to build such an environment, - such a discussion is beyond the scope of this paper. - - -2.5. Remarks - - Each of these three methods has its advantages. When used in - combination, the result is better protocols at a lower overall cost. - Backward compatible changes are best reserved for changes that do not - affect the protocol's header, and do not require that the instance - running on the other end of the connection also be changed. Protocol - evolution should be the primary way of dealing with header fields - that are no longer large enough, or when one algorithm is substituted - directly for another. New protocols should be written to off load - unexpected user demands on existing protocols, or better yet, to - - - -O'Malley & Peterson [Page 6] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - catch them before they start. - - There are also synergistic effects. First, since we know it is - possible to evolve a newly created protocol once it has been put in - place, the pressure to add unnecessary features should be reduced. - Second, the ability to create new protocols removes the pressure to - overextend a given protocol. Finally, the ability to evolve a - protocol removes the pressure to maintain backward compatibility - where it is really not possible. - - -3. TCP Extensions: A Case Study - - This section examines the effects of using our proposed methodology - to implement changes to TCP. We will begin by analyzing the backward - compatible extensions defined in RFC's 1072 and 1185, and proposing a - set of much simpler evolutionary modifications. We also analyze - several more problematical extensions to TCP, such as Transactional - TCP. Finally, we point our some areas of TCP which may require - changes in the future. - - The evolutionary modification to TCP that we propose includes all of - the functionality described in RFC's 1072 and 1185, but does not - preserve the header format. At the risk of being misunderstood as - believing backward compatibility is a good idea, we also show how our - proposed changes to TCP can be folded into a backward compatible - implementation of TCP. We do this as a courtesy for those readers - that cannot accept the possibility of multiple versions of TCP. - - -3.1. RFC's 1072 and 1185 - - 3.1.1. Round Trip Timing - - In RFC 1072, a new ECHO option is proposed that allows each TCP - packet to carry a timestamp in its header. This timestamp is used to - keep a more accurate estimate of the RTT (round trip time) used to - decide when to re-transmit segments. In the original TCP algorithm, - the sender manually times a small number of sends. The resulting - algorithm was quite complex and does not produce an accurate enough - RTT for high capacity networks. The inclusion of a timestamp in every - header both simplifies the code needed to calculate the RTT and - improves the accuracy and robustness of the algorithm. - - The new algorithm as proposed in RFC 1072 does not appear to have any - serious problems. However, the authors of RFC 1072 go to great - lengths in an attempt to keep this modification backward compatible - with the previous version of TCP. They place an ECHO option in the - - - -O'Malley & Peterson [Page 7] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - SYN segment and state, "It is likely that most implementations will - properly ignore any options in the SYN segment that they do not - understand, so new initial options should not cause problems" [4]. - This statement does not exactly inspire confidence, and we consider - the addition of an optional field to any protocol to be a de-facto, - if not a de-jure, example of an evolutionary change. Optional fields - simply attempt to hide the basic incompatibility inside the protocol, - it does not eliminate it. Therefore, since we are making an - evolutionary change anyway, the only modification to the proposed - algorithm is to move the fields into the header proper. Thus, each - header will contain 32-bit echo and echo reply fields. Two fields are - needed to handle bi-directional data streams. - - - 3.1.2. Window Size and Sequence Number Space - - Long Fat Networks (LFN's), networks which contain very high capacity - lines with very high latency, introduce the possibility that the - number of bits in transit (the bandwidth-delay product) could exceed - the TCP window size, thus making TCP the limiting factor in network - performance. Worse yet, the time it takes the sequence numbers to - wrap around could be reduced to a point below the MSL (maximum - segment lifetime), introducing the possibility of old packets being - mistakenly accepted as new. - - RFC 1072 extends the window size through the use of an implicit - constant scaling factor. The window size in the TCP header is - multiplied by this factor to get the true window size. This - algorithm has three problems. First, one must prove that at all times - the implicit scaling factor used by the sender is the same as the - receiver. The proposed algorithm appears to do so, but the - complexity of the algorithm creates the opportunity for poor - implementations to affect the correctness of TCP. Second, the use of - a scaling factor complicates the TCP implementation in general, and - can have serious effects on other parts of the protocol. - - A final problem is what we characterize as the "quantum window - sizing" problem. Assuming that the scaling factors will be powers of - two, the algorithm right shifts the receiver's window before sending - it. This effectively rounds the window size down to the nearest - multiple of the scaling factor. For large scaling factors, say 64k, - this implies that window values are all multiples of 64k and the - minimum window size is 64k; advertising a smaller window is - impossible. While this is not necessarily a problem (and it seems to - be an extreme solution to the silly window syndrome) what effect this - will have on the performance of high-speed network links is anyone's - guess. We can imagine this extension leading to future papers - entitled "A Quantum Mechanical Approach to Network Performance". - - - -O'Malley & Peterson [Page 8] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - RFC 1185 is an attempt to get around the problem of the window - wrapping too quickly without explicitly increasing the sequence - number space. Instead, the RFC proposes to use the timestamp used in - the ECHO option to weed out old duplicate messages. The algorithm - presented in RFC 1185 is complex and has been shown to be seriously - flawed at a recent End-to-End Research Group meeting. Attempts are - currently underway to fix the algorithm presented in the RFC. We - believe that this is a serious mistake. - - We see two problems with this approach on a very fundamental level. - First, we believe that making TCP depend on accurate clocks for - correctness to be a mistake. The Internet community has NO experience - with transport protocols that depend on clocks for correctness. - Second, the proposal uses two distinct schemes to deal with old - duplicate packets: the sliding window algorithm takes care of "new" - old packets (packets from the current sequence number epoch) and the - timestamp algorithm deals with "old" old packets (packets from - previous sequence number epochs). It is hard enough getting one of - these schemes to work much less to get two to work and ensure that - they do not interfere with one another. - - In RFC 1185, the statement is made that "An obvious fix for the - problem of cycling the sequence number space is to increase the size - of the TCP sequence number field." Using protocol evolution, the - obvious fix is also the correct one. The window size can be increased - to 32 bits by simply changing a short to a long in the definition of - the TCP header. At the same time, the sequence number and - acknowledgment fields can be increased to 64 bits. This change is - the minimum complexity modification to get the job done and requires - little or no analysis to be shown to work correctly. - - On machines that do not support 64-bit integers, increasing the - sequence number size is not as trivial as increasing the window size. - However, it is identical in cost to the modification proposed in RFC - 1185; the high order bits can be thought of as an optimal clock that - ticks only when it has to. Also, because we are not dealing with - real time, the problems with unreliable system clocks is avoided. On - machines that support 64-bit integers, the original TCP code may be - reused. Since only very high performance machines can hope to drive - a communications network at the rates this modification is designed - to support, and the new generation of RISC microprocessors (e.g., - MIPS R4000 and PA-RISC) do support 64-bit integers, the assumption of - 64-bit arithmetic may be more of an advantage than a liability. - - - - - - - - -O'Malley & Peterson [Page 9] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - 3.1.3. Selective Retransmission - - Another problem with TCP's support for LFN's is that the sliding - window algorithm used by TCP does not support any form of selective - acknowledgment. Thus, if a segment is lost, the total amount of data - that must be re-transmitted is some constant times the bandwidth- - delay product, despite the fact that most of the segments have in - fact arrived at the receiver. RFC 1072 proposes to extend TCP to - allow the receiver to return partial acknowledgments to the sender in - the hope that the sender will use that information to avoid - unnecessary re-transmissions. - - It has been our experience on predictable local area networks that - the performance of partial re-transmission strategies is highly non- - obvious, and it generally requires more than one iteration to find a - decent algorithm. It is therefore not surprising that the algorithm - proposed in RFC 1072 has some problems. The proposed TCP extension - allows the receiver to include a short list of received fragments - with every ACK. The idea being that when the receiver sends back a - normal ACK, it checks its queue of segments that have been received - out of order and sends the relative sequence numbers of contiguous - blocks of segments back to the sender. The sender then uses this - information to re-transmit the segments transmitted but not listed in - the ACK. - - As specified, this algorithm has two related problems: (1) it ignores - the relative frequencies of delivered and dropped packets, and (2) - the list provided in the option field is probably too short to do - much good on networks with large bandwidth-delay products. In every - model of high bandwidth networks that we have seen, the packet loss - rate is very low, and thus, the ratio of dropped packets to delivered - packets is very low. An algorithm that returns ACKs as proposed is - simply going to have to send more information than one in which the - receiver returns NAKs. - - This problem is compounded by the short size of the TCP option field - (44 bytes). In theory, since we are only worried about high bandwidth - networks, returning ACKs instead of NAKs is not really a problem; the - bandwidth is available to send any information that's needed. The - problem comes when trying to compress the ACK information into the 44 - bytes allowed. The proposed extensions effectively compresses the - ACK information by allowing the receiver to ACK byte ranges rather - than segments, and scaling the relative sequence numbers of the re- - transmitted segments. This makes it much more difficult for the - sender to tell which segments should be re-transmitted, and - complicates the re-transmission code. More importantly, one should - never compress small amounts of data being sent over a high bandwidth - network; it trades a scarce resource for an abundant resource. On - - - -O'Malley & Peterson [Page 10] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - low bandwidth networks, selective retransmission is not needed and - the SACK option should be disabled. - - We propose two solutions to this problem. First, the receiver can - examine its list of out-of-order packets and guess which segments - have been dropped, and NAK those segments back to the sender. The - number of NAKs should be low enough that one per TCP packet should be - sufficient. Note that the receiver has just as much information as - the sender about what packets should be retransmitted, and in any - case, the NAKs are simply suggestions which have no effect on - correctness. - - Our second proposed modification is to increase the offset field in - the TCP header from 4 bits to 16 bits. This allows 64k-bytes of TCP - header, which allows us to radically simplify the selective re- - transmission algorithm proposed in RFC 1072. The receiver can now - simply send a list of 64-bit sequence numbers for the out-of-order - segments to the sender. The sender can then use this information to - do a partial retransmission without needing an ouji board to - translate ACKs into segments. With the new header size, it may be - faster for the receiver to send a large list than to attempt to - aggregate segments into larger blocks. - - - 3.1.4. Header Modifications - - The modifications proposed above drastically change the size and - structure of the TCP header. This makes it a good time to re-think - the structure of the proposed TCP header. The primary goal of the - current TCP header is to save bits in the output stream. When TCP was - developed, a high bandwidth network was 56kbps, and the key use for - TCP was terminal I/O. In both situations, minimal header size was - important. Unfortunately, while the network has drastically - increased in performance and the usage pattern of the network is now - vastly different, most protocol designers still consider saving a few - bits in the header to be worth almost any price. Our basic goal is - different: to improve performance by eliminating the need to extract - information packed into odd length bit fields in the header. Below - is our first cut at such a modification. - - The protocol id field is there to make further evolutionary - modifications to TCP easier. This field basically subsumes the - protocol number field contained in the IP header with a version - number. Each distinct TCP version has a different protocol id and - this field ensures that the right code is looking at the right - header. The offset field has been increased to 16 bits to support - the larger header size required, and to simplify header processing. - The code field has been extended to 16 bits to support more options. - - - -O'Malley & Peterson [Page 11] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - The source port and destination port are unchanged. The size of both - the sequence number and ACK fields have been increased to 64 bits. - The open window field has been increased to 32 bits. The checksum and - urgent data pointer fields are unchanged. The echo and echo reply - fields are added. The option field remains but can be much larger - than in the old TCP. All headers are padded out to 32 bit - boundaries. Note that these changes increase the minimum header size - from 24 bytes (actually 36 bytes if the ECHO and ECHO reply options - defined in RFC 1072 are included on every packet) to 48 bytes. The - maximum header size has been increased to the maximum segment size. - We do not believe that the the increased header size will have a - measurable effect on protocol performance. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Protocol ID | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Offset | Code | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source | Dest | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Seq | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Ack | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Window | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Checksum | Urgent | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Echo | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Echo Reply | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Options | Pad | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - 3.1.5. Backward Compatibility - - The most likely objection to the proposed TCP extension is that it is - not backward compatible with the current version of TCP, and most - importantly, TCP's header. In this section we will present three - versions of the proposed extension with increasing degrees of - backward compatibility. The final version will combine the same - degree of backward compatibility found in the protocol described in - - - -O'Malley & Peterson [Page 12] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - RFC's 1072/1185, with the much simpler semantics described in this - RFC. - - We believe that the best way to preserve backward compatibility is to - leave all of TCP alone and support the transparent use of a new - protocol when and where it is needed. The basic scheme is the one - described in section 2.4. Those machines and operating systems that - need to support high speed connections should implement some general - protocol infrastructure that allows them to rapidly evolve protocols. - Machines that do not require such service simply keep using the - existing version of TCP. A virtual protocol is used to manage the use - of multiple TCP versions. - - This approach has several advantages. First, it guarantees backward - compatibility with ALL existing TCP versions because such - implementations will never see strange packets with new options. - Second, it supports further modification of TCP with little - additional costs. Finally, since our version of TCP will more closely - resemble the existing TCP protocol than that proposed in RFC's - 1072/1185, the cost of maintaining two simple protocols will probably - be lower than maintaining one complex protocol. (Note that with high - probability you still have to maintain two versions of TCP in any - case.) The only additional cost is the memory required for keeping - around two copies of TCP. - - For those that insist that the only efficient way to implement TCP - modifications is in a single monolithic protocol, or those that - believe that the space requirements of two protocols would be too - great, we simply migrate the virtual protocol into TCP. TCP is - modified so that when opening a connection, the sender uses the TCP - VERSION option attached to the SYN packet to request using the new - version. The receiver responds with a TCP VERSION ACK in the SYN ACK - packet, after which point, the new header format described in Section - 3.1.4 is used. Thus, there is only one version of TCP, but that - version supports multiple header formats. The complexity of such a - protocol would be no worse than the protocol described in RFC - 1072/1185. It does, however, make it more difficult to make - additional changes to TCP. - - Finally, for those that believe that the preservation of the TCP's - header format has any intrinsic value (e.g., for those that don't - want to re-program their ethernet monitors), a header compatible - version of our proposal is possible. One simply takes all of the - additional information contained in the header given in Section 3.1.4 - and places it into a single optional field. Thus, one could define a - new TCP option which consists of the top 32 bits of the sequence and - ack fields, the echo and echo_reply fields, and the top 16 bits of - the window field. This modification makes it more difficult to take - - - -O'Malley & Peterson [Page 13] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - advantage of machines with 64-bit address spaces, but at a minimum - will be just as easy to process as the protocol described in RFC - 1072/1185. The only restriction is that the size of the header - option field is still limited to 44 bytes, and thus, selective - retransmission using NAKs rather than ACKs will probably be required. - - The key observation is that one should make a protocol extension - correct and simple before trying to make it backward compatible. As - far as we can tell, the only advantages possessed by the protocol - described in RFC 1072/1185 is that its typical header, size including - options, is 8 to 10 bytes shorter. The price for this "advantage" is - a protocol of such complexity that it may prove impossible for normal - humans to implement. Trying to maintain backward compatibility at - every stage of the protocol design process is a serious mistake. - - -3.2. TCP Over Extension - - Another potential problem with TCP that has been discussed recently, - but has not yet resulted in the generation of an RFC, is the - potential for TCP to grab and hold all 2**16 port numbers on a given - machine. This problem is caused by short port numbers, long MSLs, - and the misuse of TCP as a request-reply protocol. TCP must hold onto - each port after a close until all possible messages to that port have - died, about 240 seconds. Even worse, this time is not decreasing with - increase network performance. With new fast hardware, it is possible - for an application to open a TCP connection, send data, get a reply, - and close the connection at a rate fast enough to use up all the - ports in less than 240 seconds. This usage pattern is generated by - people using TCP for something it was never intended to do--- - guaranteeing at-most-once semantics for remote procedure calls. - - The proposed solution is to embed an RPC protocol into TCP while - preserving backward compatibility. This is done by piggybacking the - request message on the SYN packet and the reply message on the SYN- - ACK packet. This approach suffers from one key problem: it reduces - the probability of a correct TCP implementation to near 0. The basic - problem has nothing to do with TCP, rather it is the lack of an - Internet request-reply protocol that guarantees at-most-once - semantics. - - We propose to solve this problem by the creation of a new protocol. - This has already been attempted with VMTP, but the size and - complexity of VMTP, coupled with the process currently required to - standardize a new protocol doomed it from the start. Instead of - solving the general problem, we propose to use Sprite RPC [7], a much - simpler protocol, as a means of off-loading inappropriate users from - TCP. - - - -O'Malley & Peterson [Page 14] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - The basic design would attempt to preserve as much of the TCP - interface as possible in order that current TCP (mis)users could be - switched to Sprite RPC without requiring code modification on their - part. A virtual protocol could be used to select the correct protocol - TCP or Sprite RPC if it exists on the other machine. A backward - compatible modification to TCP could be made which would simply - prevent it from grabbing all of the ports by refusing connections. - This would encourage TCP abusers to use the new protocol. - - Sprite RPC, which is designed for a local area network, has two - problems when extended into the Internet. First, it does not have a - usefully flow control algorithm. Second, it lacks the necessary - semantics to reliably tear down connections. The lack of a tear down - mechanism needs to be solved, but the flow control problem could be - dealt with in later iterations of the protocol as Internet blast - protocols are not yet well understood; for now, we could simple limit - the size of each message to 16k or 32k bytes. This might also be a - good place to use a decomposed version of Sprite RPC [2], which - exposes each of these features as separate protocols. This would - permit the quick change of algorithms, and once the protocol had - stabilized, a monolithic version could be constructed and distributed - to replace the decomposed version. - - In other words, the basic strategy is to introduce as simple of RPC - protocol as possible today, and later evolve this protocol to address - the known limitations. - - -3.3. Future Modifications - - The header prediction algorithm should be generalized so as to be - less sensitive to changes in the protocols header and algorithm. - There almost seems to be as much effort to make all modifications to - TCP backward compatible with header prediction as there is to make - them backward compatible with TCP. The question that needs to be - answered is: are there any changes we can made to TCP to make header - prediction easier, including the addition of information into the - header. In [6], the authors showed how one might generalize - optimistic blast from VMTP to almost any protocol that performs - fragmentation and reassembly. Generalizing header prediction so that - it scales with TCP modification would be step in the right direction. - - It is clear that an evolutionary change to increase the size of the - source and destination ports in the TCP header will eventually be - necessary. We also believe that TCP could be made significantly - simpler and more flexible through the elimination of the pseudo- - header. The solution to this problem is to simply add a length field - and the IP address of the destination to the TCP header. It has also - - - -O'Malley & Peterson [Page 15] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - been mentioned that better and simpler TCP connection establishment - algorithms would be useful. Some form of reliable record stream - protocol should be developed. Performing sliding window and flow - control over records rather than bytes would provide numerous - opportunities for optimizations and allow TCP to return to its - original purpose as a byte-stream protocol. Finally, it has become - clear to us that the current Internet congestion control strategy is - to use TCP for everything since it is the only protocol that supports - congestion control. One of the primary reasons many "new protocols" - are proposed as TCP options is that it is the only way to get at - TCP's congestion control. At some point, a TCP-independent congestion - control scheme must be implemented and one might then be able to - remove the existing congestion control from TCP and radically - simplify the protocol. - - -4. Discussion - - One obvious side effect of the changes we propose is to increase the - size of the TCP header. In some sense, this is inevitable; just about - every field in the header has been pushed to its limit by the radical - growth of the network. However, we have made very little effort to - make the minimal changes to solve the current problem. In fact, we - have tended to sacrifice header size in order to defer future changes - as long as possible. The problem with this is that one of TCP's - claims to fame is its efficiency at sending small one byte packets - over slow networks. Increasing the size of the TCP header will - inevitably result in some increase in overhead on small packets on - slow networks. Clark among others have stated that they see no - fundamental performance limitations that would prevent TCP from - supporting very high speed networks. This is true as far as it goes; - there seems to be a direct trade-off between TCP performance on high - speed networks and TCP performance on slow speed networks. The - dynamic range is simply too great to be optimally supported by one - protocol. Hence, in keeping around the old version of TCP we have - effectively split TCP into two protocols, one for high bandwidth - lines and the other for low bandwidth lines. - - Another potential argument is that all of the changes mentioned above - should be packaged together as a new version of TCP. This version - could be standardized and we could all go back to the status quo of - stable unchanging protocols. While to a certain extent this is - inevitable---there is a backlog of necessary TCP changes because of - the current logistical problems in modifying protocols---it is only - begs the question. The status quo is simply unacceptably static; - there will always be future changes to TCP. Evolutionary change will - also result in a better and more reliable TCP. Making small changes - and distributing them at regular intervals ensures that one change - - - -O'Malley & Peterson [Page 16] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - has actually been stabilized before the next has been made. It also - presents a more balanced workload to the protocol designer; rather - than designing one new protocol every 10 years he makes annual - protocol extensions. It will also eventually make protocol - distribution easier: the basic problem with protocol distribution now - is that it is done so rarely that no one knows how to do it and there - is no incentive to develop the infrastructure needed to perform the - task efficiently. While the first protocol distribution is almost - guaranteed to be a disaster, the problem will get easier with each - additional one. Finally, such a new TCP would have the same problems - as VMTP did; a radically new protocol presents a bigger target. - - The violation of backward compatibility in systems as complex as the - Internet is always a serious step. However, backward compatibility is - a technique, not a religion. Two facts are often overlooked when - backward compatibility gets out of hand. First, violating backward - compatibility is always a big win when you can get away with it. One - of the key advantages of RISC chips over CISC chips is simply that - they were not backward compatible with anything. Thus, they were not - bound by design decisions made when compilers were stupid and real - men programmed in assembler. Second, one is going to have to break - backward compatibility at some point anyway. Every system has some - headroom limitations which result in either stagnation (IBM mainframe - software) or even worse, accidental violations of backward - compatibility. - - Of course, the biggest problem with our approach is that it is not - compatible with the existing standardization process. We hope to be - able to design and distribute protocols in less time than it takes a - standards committee to agree on an acceptable meeting time. This is - inevitable because the basic problem with networking is the - standardization process. Over the last several years, there has been - a push in the research community for lightweight protocols, when in - fact what is needed are lightweight standards. Also note that we - have not proposed to implement some entirely new set of "superior" - communications protocols, we have simply proposed a system for making - necessary changes to the existing protocol suites fast enough to keep - up with the underlying change in the network. In fact, the first - standards organization that realizes that the primary impediment to - standardization is poor logistical support will probably win. - - -5. Conclusions - - The most important conclusion of this RFC is that protocol change - happens and is currently happening at a very respectable clip. While - all of the changes given as example in this document are from TCP, - there are many other protocols that require modification. In a more - - - -O'Malley & Peterson [Page 17] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - prosaic domain, the telephone company is running out of phone - numbers; they are being overrun by fax machines, modems, and cars. - The underlying cause of these problems seems to be an consistent - exponential increase almost all network metrics: number of hosts, - bandwidth, host performance, applications, and so on, combined with - an attempt to run the network with a static set of unchanging network - protocols. This has been shown to be impossible and one can almost - feel the pressure for protocol change building. We simply propose to - explicitly deal with the changes rather keep trying to hold back the - flood. - - Of almost equal importance is the observation that TCP is a protocol - and not a platform for implementing other protocols. Because of a - lack of any alternatives, TCP has become a de-facto platform for - implementing other protocols. It provides a vague standard interface - with the kernel, it runs on many machines, and has a well defined - distribution path. Otherwise sane people have proposed Bounded Time - TCP (an unreliable byte stream protocol), Simplex TCP (which supports - data in only one direction) and Multi-cast TCP (too horrible to even - consider). All of these protocols probably have their uses, but not - as TCP options. The fact that a large number of people are willing to - use TCP as a protocol implementation platform points to the desperate - need for a protocol independent platform. - - Finally, we point out that in our research we have found very little - difference in the actual technical work involved with the three - proposed methods of protocol modification. The amount of work - involved in a backward compatible change is often more than that - required for an evolutionary change or the creation of a new - protocol. Even the distribution costs seem to be identical. The - primary cost difference between the three approaches is the cost of - getting the modification approved. A protocol modification, no matter - how extensive or bizarre, seems to incur much less cost and risk. It - is time to stop changing the protocols to fit our current way of - thinking, and start changing our way of thinking to fit the - protocols. - - -6. References - - -[1] Cheriton D., "VMTP: Versatile Message Transaction Protocol", RFC - 1045, Stanford University, February 1988. - - -[2] Hutchinson, N., Peterson, L., Abbott, M., and S. O'Malley, "RPC in - the x-Kernel: Evaluating New Design Techniques", Proceedings of the - 12th Symposium on Operating System Principles, Pgs. 91-101, - - - -O'Malley & Peterson [Page 18] - -RFC 1263 TCP Extensions Considered Harmful October 1991 - - - December 1989. - - -[3] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM '88, - August 1988. - - -[4] Jacobson, V., and R. Braden, "TCP Extensions for Long-Delay Paths", - RFC 1072, LBL, ISI, October 1988. - - -[5] Jacobson, V., Braden, R., and L. Zhang, "TCP Extensions for High- - Speed Paths", RFC 1185, LBL, ISI, PARC, October 1990. - - -[6] O'Malley, S., Abbott, M., Hutchinson, N., and L. Peterson, "A Tran- - sparent Blast Facility", Journal of Internetworking, Vol. 1, No. - 2, Pgs. 57-75, December 1990. - - -[7] Welch, B., "The Sprite Remote Procedure Call System", UCB/CSD - 86/302, University of California at Berkeley, June 1988. - -7. Security Considerations - - Security issues are not discussed in this memo. - - -8. Authors' Addresses - - Larry L. Peterson - University of Arizona - Department of Computer Sciences - Tucson, AZ 85721 - - Phone: (602) 621-4231 - EMail: llp@cs.arizona.edu - - - Sean O'Malley - University of Arizona - Department of Computer Sciences - Tucson, AZ 85721 - - Phone: 602-621-8373 - EMail: sean@cs.arizona.edu - - - - - -O'Malley & Peterson [Page 19] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1332.txt b/ext/picotcp/RFC/rfc1332.txt deleted file mode 100644 index 3e12042..0000000 --- a/ext/picotcp/RFC/rfc1332.txt +++ /dev/null @@ -1,787 +0,0 @@ - - - - - - -Network Working Group G. McGregor -Request for Comments: 1332 Merit -Obsoletes: RFC 1172 May 1992 - - - - The PPP Internet Protocol Control Protocol (IPCP) - - - -Status of this Memo - - This RFC specifies an IAB standards track protocol for the Internet - community, and requests discussion and suggestions for improvements. - Please refer to the current edition of the "IAB Official Protocol - Standards" for the standardization state and status of this protocol. - Distribution of this memo is unlimited. - -Abstract - - The Point-to-Point Protocol (PPP) [1] provides a standard method of - encapsulating Network Layer protocol information over point-to-point - links. PPP also defines an extensible Link Control Protocol, and - proposes a family of Network Control Protocols (NCPs) for - establishing and configuring different network-layer protocols. - - This document defines the NCP for establishing and configuring the - Internet Protocol [2] over PPP, and a method to negotiate and use Van - Jacobson TCP/IP header compression [3] with PPP. - - This RFC is a product of the Point-to-Point Protocol Working Group of - the Internet Engineering Task Force (IETF). - - - - - - - - - - - - - - - - - - - -McGregor [Page i] - -RFC 1332 PPP IPCP May 1992 - - -Table of Contents - - - 1. Introduction .......................................... 1 - - 2. A PPP Network Control Protocol (NCP) for IP ........... 2 - 2.1 Sending IP Datagrams ............................ 2 - - 3. IPCP Configuration Options ............................ 4 - 3.1 IP-Addresses .................................... 5 - 3.2 IP-Compression-Protocol ......................... 6 - 3.3 IP-Address ...................................... 8 - - 4. Van Jacobson TCP/IP header compression ................ 9 - 4.1 Configuration Option Format ..................... 9 - - APPENDICES ................................................... 11 - - A. IPCP Recommended Options .............................. 11 - - SECURITY CONSIDERATIONS ...................................... 11 - - REFERENCES ................................................... 11 - - ACKNOWLEDGEMENTS ............................................. 11 - - CHAIR'S ADDRESS .............................................. 12 - - AUTHOR'S ADDRESS ............................................. 12 - - - - - - - - - - - - - - - - - - - - - - -McGregor [Page ii] - -RFC 1332 PPP IPCP May 1992 - - -1. Introduction - - PPP has three main components: - - 1. A method for encapsulating datagrams over serial links. - - 2. A Link Control Protocol (LCP) for establishing, configuring, - and testing the data-link connection. - - 3. A family of Network Control Protocols (NCPs) for establishing - and configuring different network-layer protocols. - - In order to establish communications over a point-to-point link, each - end of the PPP link must first send LCP packets to configure and test - the data link. After the link has been established and optional - facilities have been negotiated as needed by the LCP, PPP must send - NCP packets to choose and configure one or more network-layer - protocols. Once each of the chosen network-layer protocols has been - configured, datagrams from each network-layer protocol can be sent - over the link. - - The link will remain configured for communications until explicit LCP - or NCP packets close the link down, or until some external event - occurs (an inactivity timer expires or network administrator - intervention). - - - - - - - - - - - - - - - - - - - - - - - - - - -McGregor [Page 1] - -RFC 1332 PPP IPCP May 1992 - - -2. A PPP Network Control Protocol (NCP) for IP - - The IP Control Protocol (IPCP) is responsible for configuring, - enabling, and disabling the IP protocol modules on both ends of the - point-to-point link. IPCP uses the same packet exchange machanism as - the Link Control Protocol (LCP). IPCP packets may not be exchanged - until PPP has reached the Network-Layer Protocol phase. IPCP packets - received before this phase is reached should be silently discarded. - - The IP Control Protocol is exactly the same as the Link Control - Protocol [1] with the following exceptions: - - Data Link Layer Protocol Field - - Exactly one IPCP packet is encapsulated in the Information field - of PPP Data Link Layer frames where the Protocol field indicates - type hex 8021 (IP Control Protocol). - - Code field - - Only Codes 1 through 7 (Configure-Request, Configure-Ack, - Configure-Nak, Configure-Reject, Terminate-Request, Terminate-Ack - and Code-Reject) are used. Other Codes should be treated as - unrecognized and should result in Code-Rejects. - - Timeouts - - IPCP packets may not be exchanged until PPP has reached the - Network-Layer Protocol phase. An implementation should be - prepared to wait for Authentication and Link Quality Determination - to finish before timing out waiting for a Configure-Ack or other - response. It is suggested that an implementation give up only - after user intervention or a configurable amount of time. - - Configuration Option Types - - IPCP has a distinct set of Configuration Options, which are - defined below. - -2.1. Sending IP Datagrams - - Before any IP packets may be communicated, PPP must reach the - Network-Layer Protocol phase, and the IP Control Protocol must reach - the Opened state. - - Exactly one IP packet is encapsulated in the Information field of PPP - Data Link Layer frames where the Protocol field indicates type hex - 0021 (Internet Protocol). - - - -McGregor [Page 2] - -RFC 1332 PPP IPCP May 1992 - - - The maximum length of an IP packet transmitted over a PPP link is the - same as the maximum length of the Information field of a PPP data - link layer frame. Larger IP datagrams must be fragmented as - necessary. If a system wishes to avoid fragmentation and reassembly, - it should use the TCP Maximum Segment Size option [4], and MTU - discovery [5]. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McGregor [Page 3] - -RFC 1332 PPP IPCP May 1992 - - -3. IPCP Configuration Options - -IPCP Configuration Options allow negotiatiation of desirable Internet -Protocol parameters. IPCP uses the same Configuration Option format -defined for LCP [1], with a separate set of Options. - -The most up-to-date values of the IPCP Option Type field are specified -in the most recent "Assigned Numbers" RFC [6]. Current values are -assigned as follows: - - 1 IP-Addresses - 2 IP-Compression-Protocol - 3 IP-Address - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McGregor [Page 4] - -RFC 1332 PPP IPCP May 1992 - - -3.1. IP-Addresses - - Description - - The use of the Configuration Option IP-Addresses has been - deprecated. It has been determined through implementation - experience that it is difficult to ensure negotiation convergence - in all cases using this option. RFC 1172 [7] provides information - for implementations requiring backwards compatability. The IP- - Address Configuration Option replaces this option, and its use is - preferred. - - This option SHOULD NOT be sent in a Configure-Request if a - Configure-Request has been received which includes either an IP- - Addresses or IP-Address option. This option MAY be sent if a - Configure-Reject is received for the IP-Address option, or a - Configure-Nak is received with an IP-Addresses option as an - appended option. - - Support for this option MAY be removed after the IPCP protocol - status advances to Internet Draft Standard. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McGregor [Page 5] - -RFC 1332 PPP IPCP May 1992 - - -3.2. IP-Compression-Protocol - - Description - - This Configuration Option provides a way to negotiate the use of a - specific compression protocol. By default, compression is not - enabled. - - A summary of the IP-Compression-Protocol Configuration Option format - is shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | IP-Compression-Protocol | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data ... - +-+-+-+-+ - - Type - - 2 - - Length - - >= 4 - - IP-Compression-Protocol - - The IP-Compression-Protocol field is two octets and indicates the - compression protocol desired. Values for this field are always - the same as the PPP Data Link Layer Protocol field values for that - same compression protocol. - - The most up-to-date values of the IP-Compression-Protocol field - are specified in the most recent "Assigned Numbers" RFC [6]. - Current values are assigned as follows: - - Value (in hex) Protocol - - 002d Van Jacobson Compressed TCP/IP - - Data - - The Data field is zero or more octets and contains additional data - as determined by the particular compression protocol. - - - - - -McGregor [Page 6] - -RFC 1332 PPP IPCP May 1992 - - - Default - - No compression protocol enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McGregor [Page 7] - -RFC 1332 PPP IPCP May 1992 - - -3.3. IP-Address - - Description - - This Configuration Option provides a way to negotiate the IP - address to be used on the local end of the link. It allows the - sender of the Configure-Request to state which IP-address is - desired, or to request that the peer provide the information. The - peer can provide this information by NAKing the option, and - returning a valid IP-address. - - If negotiation about the remote IP-address is required, and the - peer did not provide the option in its Configure-Request, the - option SHOULD be appended to a Configure-Nak. The value of the - IP-address given must be acceptable as the remote IP-address, or - indicate a request that the peer provide the information. - - By default, no IP address is assigned. - - A summary of the IP-Address Configuration Option format is shown - below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | IP-Address - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - IP-Address (cont) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 3 - - Length - - 6 - - IP-Address - - The four octet IP-Address is the desired local address of the - sender of a Configure-Request. If all four octets are set to - zero, it indicates a request that the peer provide the IP-Address - information. - - Default - - No IP address is assigned. - - - -McGregor [Page 8] - -RFC 1332 PPP IPCP May 1992 - - -4. Van Jacobson TCP/IP header compression - -Van Jacobson TCP/IP header compression reduces the size of the TCP/IP -headers to as few as three bytes. This can be a significant improvement -on slow serial lines, particularly for interactive traffic. - -The IP-Compression-Protocol Configuration Option is used to indicate the -ability to receive compressed packets. Each end of the link must -separately request this option if bi-directional compression is desired. - -The PPP Protocol field is set to the following values when transmitting -IP packets: - - Value (in hex) - - 0021 Type IP. The IP protocol is not TCP, or the packet is a - fragment, or cannot be compressed. - - 002d Compressed TCP. The TCP/IP headers are replaced by the - compressed header. - - 002f Uncompressed TCP. The IP protocol field is replaced by - the slot identifier. - -4.1. Configuration Option Format - - A summary of the IP-Compression-Protocol Configuration Option format - to negotiate Van Jacobson TCP/IP header compression is shown below. - The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | IP-Compression-Protocol | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Max-Slot-Id | Comp-Slot-Id | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 2 - - Length - - 6 - - - - - - -McGregor [Page 9] - -RFC 1332 PPP IPCP May 1992 - - - IP-Compression-Protocol - - 002d (hex) for Van Jacobson Compressed TCP/IP headers. - - Max-Slot-Id - - The Max-Slot-Id field is one octet and indicates the maximum slot - identifier. This is one less than the actual number of slots; the - slot identifier has values from zero to Max-Slot-Id. - - Note: There may be implementations that have problems with only - one slot (Max-Slot-Id = 0). See the discussion in reference - [3]. The example implementation in [3] will only work with 3 - through 254 slots. - - Comp-Slot-Id - - The Comp-Slot-Id field is one octet and indicates whether the slot - identifier field may be compressed. - - 0 The slot identifier must not be compressed. All compressed - TCP packets must set the C bit in every change mask, and - must include the slot identifier. - - 1 The slot identifer may be compressed. - - The slot identifier must not be compressed if there is no ability - for the PPP link level to indicate an error in reception to the - decompression module. Synchronization after errors depends on - receiving a packet with the slot identifier. See the discussion - in reference [3]. - - - - - - - - - - - - - - - - - - - - -McGregor [Page 10] - -RFC 1332 PPP IPCP May 1992 - - -A. IPCP Recommended Options - - The following Configurations Options are recommended: - - IP-Compression-Protocol -- with at least 4 slots, usually 16 - slots. - - IP-Address -- only on dial-up lines. - - -Security Considerations - - Security issues are not discussed in this memo. - - -References - - [1] Simpson, W., "The Point-to-Point Protocol", RFC 1331, May 1992. - - [2] Postel, J., "Internet Protocol", RFC 791, USC/Information - Sciences Institute, September 1981. - - [3] Jacobson, V., "Compressing TCP/IP Headers", RFC 1144, January - 1990. - - [4] Postel, J., "The TCP Maximum Segment Size Option and Related - Topics", RFC 879, USC/Information Sciences Institute, November - 1983. - - [5] Mogul, J., and S. Deering, "Path MTU Discovery", RFC 1191, - November 1990. - - [6] Reynolds, J., and J. Postel, "Assigned Numbers", RFC 1060, - USC/Information Sciences Institute, March 1990. - - [7] Perkins, D., and R. Hobby, "Point-to-Point Protocol (PPP) - initial configuration options", RFC 1172, August 1990. - - -Acknowledgments - - Some of the text in this document is taken from RFCs 1171 & 1172, by - Drew Perkins of Carnegie Mellon University, and by Russ Hobby of the - University of California at Davis. - - Information leading to the expanded IP-Compression option provided by - Van Jacobson at SIGCOMM '90. - - - - -McGregor [Page 11] - -RFC 1332 PPP IPCP May 1992 - - - Bill Simpson helped with the document formatting. - - -Chair's Address - - The working group can be contacted via the current chair: - - Brian Lloyd - Lloyd & Associates - 3420 Sudbury Road - Cameron Park, California 95682 - - Phone: (916) 676-1147 - - EMail: brian@ray.lloyd.com - - - -Author's Address - - Questions about this memo can also be directed to: - - Glenn McGregor - Merit Network, Inc. - 1071 Beal Avenue - Ann Arbor, MI 48109-2103 - - Phone: (313) 763-1203 - - EMail: Glenn.McGregor@Merit.edu - - - - - - - - - - - - - - - - - - - - - -McGregor [Page 12] - diff --git a/ext/picotcp/RFC/rfc1334.txt b/ext/picotcp/RFC/rfc1334.txt deleted file mode 100644 index 6051f48..0000000 --- a/ext/picotcp/RFC/rfc1334.txt +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group B. Lloyd -Request for Comments: 1334 L&A - W. Simpson - Daydreamer - October 1992 - - - PPP Authentication Protocols - -Status of this Memo - - This RFC specifies an IAB standards track protocol for the Internet - community, and requests discussion and suggestions for improvements. - Please refer to the current edition of the "IAB Official Protocol - Standards" for the standardization state and status of this protocol. - Distribution of this memo is unlimited. - -Abstract - - The Point-to-Point Protocol (PPP) [1] provides a standard method of - encapsulating Network Layer protocol information over point-to-point - links. PPP also defines an extensible Link Control Protocol, which - allows negotiation of an Authentication Protocol for authenticating - its peer before allowing Network Layer protocols to transmit over the - link. - - This document defines two protocols for Authentication: the Password - Authentication Protocol and the Challenge-Handshake Authentication - Protocol. This memo is the product of the Point-to-Point Protocol - Working Group of the Internet Engineering Task Force (IETF). - Comments on this memo should be submitted to the ietf-ppp@ucdavis.edu - mailing list. - -Table of Contents - - 1. Introduction ............................................... 2 - 1.1 Specification Requirements ................................. 2 - 1.2 Terminology ................................................ 3 - 2. Password Authentication Protocol ............................ 3 - 2.1 Configuration Option Format ................................ 4 - 2.2 Packet Format .............................................. 5 - 2.2.1 Authenticate-Request ..................................... 5 - 2.2.2 Authenticate-Ack and Authenticate-Nak .................... 7 - 3. Challenge-Handshake Authentication Protocol.................. 8 - 3.1 Configuration Option Format ................................ 9 - 3.2 Packet Format .............................................. 10 - 3.2.1 Challenge and Response ................................... 11 - 3.2.2 Success and Failure ...................................... 13 - - - -Lloyd & Simpson [Page 1] - -RFC 1334 PPP Authentication October 1992 - - - SECURITY CONSIDERATIONS ........................................ 14 - REFERENCES ..................................................... 15 - ACKNOWLEDGEMENTS ............................................... 16 - CHAIR'S ADDRESS ................................................ 16 - AUTHOR'S ADDRESS ............................................... 16 - -1. Introduction - - PPP has three main components: - - 1. A method for encapsulating datagrams over serial links. - - 2. A Link Control Protocol (LCP) for establishing, configuring, - and testing the data-link connection. - - 3. A family of Network Control Protocols (NCPs) for establishing - and configuring different network-layer protocols. - - In order to establish communications over a point-to-point link, each - end of the PPP link must first send LCP packets to configure the data - link during Link Establishment phase. After the link has been - established, PPP provides for an optional Authentication phase before - proceeding to the Network-Layer Protocol phase. - - By default, authentication is not mandatory. If authentication of - the link is desired, an implementation MUST specify the - Authentication-Protocol Configuration Option during Link - Establishment phase. - - These authentication protocols are intended for use primarily by - hosts and routers that connect to a PPP network server via switched - circuits or dial-up lines, but might be applied to dedicated links as - well. The server can use the identification of the connecting host - or router in the selection of options for network layer negotiations. - - This document defines the PPP authentication protocols. The Link - Establishment and Authentication phases, and the Authentication- - Protocol Configuration Option, are defined in The Point-to-Point - Protocol (PPP) [1]. - -1.1. Specification Requirements - - In this document, several words are used to signify the requirements - of the specification. These words are often capitalized. - - MUST - This word, or the adjective "required", means that the definition - is an absolute requirement of the specification. - - - -Lloyd & Simpson [Page 2] - -RFC 1334 PPP Authentication October 1992 - - - MUST NOT - This phrase means that the definition is an absolute prohibition - of the specification. - - SHOULD - This word, or the adjective "recommended", means that there may - exist valid reasons in particular circumstances to ignore this - item, but the full implications should be understood and carefully - weighed before choosing a different course. - - MAY - This word, or the adjective "optional", means that this item is - one of an allowed set of alternatives. An implementation which - does not include this option MUST be prepared to interoperate with - another implementation which does include the option. - -1.2. Terminology - - This document frequently uses the following terms: - - authenticator - The end of the link requiring the authentication. The - authenticator specifies the authentication protocol to be used in - the Configure-Request during Link Establishment phase. - - peer - The other end of the point-to-point link; the end which is being - authenticated by the authenticator. - - silently discard - This means the implementation discards the packet without further - processing. The implementation SHOULD provide the capability of - logging the error, including the contents of the silently - discarded packet, and SHOULD record the event in a statistics - counter. - -2. Password Authentication Protocol - - The Password Authentication Protocol (PAP) provides a simple method - for the peer to establish its identity using a 2-way handshake. This - is done only upon initial link establishment. - - After the Link Establishment phase is complete, an Id/Password pair - is repeatedly sent by the peer to the authenticator until - authentication is acknowledged or the connection is terminated. - - PAP is not a strong authentication method. Passwords are sent over - the circuit "in the clear", and there is no protection from playback - - - -Lloyd & Simpson [Page 3] - -RFC 1334 PPP Authentication October 1992 - - - or repeated trial and error attacks. The peer is in control of the - frequency and timing of the attempts. - - Any implementations which include a stronger authentication method - (such as CHAP, described below) MUST offer to negotiate that method - prior to PAP. - - This authentication method is most appropriately used where a - plaintext password must be available to simulate a login at a remote - host. In such use, this method provides a similar level of security - to the usual user login at the remote host. - - Implementation Note: It is possible to limit the exposure of the - plaintext password to transmission over the PPP link, and avoid - sending the plaintext password over the entire network. When the - remote host password is kept as a one-way transformed value, and - the algorithm for the transform function is implemented in the - local server, the plaintext password SHOULD be locally transformed - before comparison with the transformed password from the remote - host. - -2.1. Configuration Option Format - - A summary of the Authentication-Protocol Configuration Option format - to negotiate the Password Authentication Protocol is shown below. - The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Authentication-Protocol | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 3 - - Length - - 4 - - Authentication-Protocol - - c023 (hex) for Password Authentication Protocol. - - Data - - There is no Data field. - - - -Lloyd & Simpson [Page 4] - -RFC 1334 PPP Authentication October 1992 - - -2.2. Packet Format - - Exactly one Password Authentication Protocol packet is encapsulated - in the Information field of a PPP Data Link Layer frame where the - protocol field indicates type hex c023 (Password Authentication - Protocol). A summary of the PAP packet format is shown below. The - fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data ... - +-+-+-+-+ - - Code - - The Code field is one octet and identifies the type of PAP packet. - PAP Codes are assigned as follows: - - 1 Authenticate-Request - 2 Authenticate-Ack - 3 Authenticate-Nak - - Identifier - - The Identifier field is one octet and aids in matching requests - and replies. - - Length - - The Length field is two octets and indicates the length of the PAP - packet including the Code, Identifier, Length and Data fields. - Octets outside the range of the Length field should be treated as - Data Link Layer padding and should be ignored on reception. - - Data - - The Data field is zero or more octets. The format of the Data - field is determined by the Code field. - -2.2.1. Authenticate-Request - - Description - - The Authenticate-Request packet is used to begin the Password - Authentication Protocol. The link peer MUST transmit a PAP packet - - - -Lloyd & Simpson [Page 5] - -RFC 1334 PPP Authentication October 1992 - - - with the Code field set to 1 (Authenticate-Request) during the - Authentication phase. The Authenticate-Request packet MUST be - repeated until a valid reply packet is received, or an optional - retry counter expires. - - The authenticator SHOULD expect the peer to send an Authenticate- - Request packet. Upon reception of an Authenticate-Request packet, - some type of Authenticate reply (described below) MUST be - returned. - - Implementation Note: Because the Authenticate-Ack might be - lost, the authenticator MUST allow repeated Authenticate- - Request packets after completing the Authentication phase. - Protocol phase MUST return the same reply Code returned when - the Authentication phase completed (the message portion MAY be - different). Any Authenticate-Request packets received during - any other phase MUST be silently discarded. - - When the Authenticate-Nak is lost, and the authenticator - terminates the link, the LCP Terminate-Request and Terminate- - Ack provide an alternative indication that authentication - failed. - - A summary of the Authenticate-Request packet format is shown below. - The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Peer-ID Length| Peer-Id ... - +-+-+-+-+-+-+-+-+-+-+-+-+ - | Passwd-Length | Password ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Code - - 1 for Authenticate-Request. - - Identifier - - The Identifier field is one octet and aids in matching requests - and replies. The Identifier field MUST be changed each time an - Authenticate-Request packet is issued. - - - - - - -Lloyd & Simpson [Page 6] - -RFC 1334 PPP Authentication October 1992 - - - Peer-ID-Length - - The Peer-ID-Length field is one octet and indicates the length of - the Peer-ID field. - - Peer-ID - - The Peer-ID field is zero or more octets and indicates the name of - the peer to be authenticated. - - Passwd-Length - - The Passwd-Length field is one octet and indicates the length of - the Password field. - - Password - - The Password field is zero or more octets and indicates the - password to be used for authentication. - -2.2.2. Authenticate-Ack and Authenticate-Nak - - Description - - If the Peer-ID/Password pair received in an Authenticate-Request - is both recognizable and acceptable, then the authenticator MUST - transmit a PAP packet with the Code field set to 2 (Authenticate- - Ack). - - If the Peer-ID/Password pair received in a Authenticate-Request is - not recognizable or acceptable, then the authenticator MUST - transmit a PAP packet with the Code field set to 3 (Authenticate- - Nak), and SHOULD take action to terminate the link. - - A summary of the Authenticate-Ack and Authenticate-Nak packet format - is shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Msg-Length | Message ... - +-+-+-+-+-+-+-+-+-+-+-+-+- - - Code - - 2 for Authenticate-Ack; - - - -Lloyd & Simpson [Page 7] - -RFC 1334 PPP Authentication October 1992 - - - 3 for Authenticate-Nak. - - Identifier - - The Identifier field is one octet and aids in matching requests - and replies. The Identifier field MUST be copied from the - Identifier field of the Authenticate-Request which caused this - reply. - - Msg-Length - - The Msg-Length field is one octet and indicates the length of the - Message field. - - Message - - The Message field is zero or more octets, and its contents are - implementation dependent. It is intended to be human readable, - and MUST NOT affect operation of the protocol. It is recommended - that the message contain displayable ASCII characters 32 through - 126 decimal. Mechanisms for extension to other character sets are - the topic of future research. - -3. Challenge-Handshake Authentication Protocol - - The Challenge-Handshake Authentication Protocol (CHAP) is used to - periodically verify the identity of the peer using a 3-way handshake. - This is done upon initial link establishment, and MAY be repeated - anytime after the link has been established. - - After the Link Establishment phase is complete, the authenticator - sends a "challenge" message to the peer. The peer responds with a - value calculated using a "one-way hash" function. The authenticator - checks the response against its own calculation of the expected hash - value. If the values match, the authentication is acknowledged; - otherwise the connection SHOULD be terminated. - - CHAP provides protection against playback attack through the use of - an incrementally changing identifier and a variable challenge value. - The use of repeated challenges is intended to limit the time of - exposure to any single attack. The authenticator is in control of - the frequency and timing of the challenges. - - This authentication method depends upon a "secret" known only to the - authenticator and that peer. The secret is not sent over the link. - This method is most likely used where the same secret is easily - accessed from both ends of the link. - - - - -Lloyd & Simpson [Page 8] - -RFC 1334 PPP Authentication October 1992 - - - Implementation Note: CHAP requires that the secret be available in - plaintext form. To avoid sending the secret over other links in - the network, it is recommended that the challenge and response - values be examined at a central server, rather than each network - access server. Otherwise, the secret SHOULD be sent to such - servers in a reversably encrypted form. - - The CHAP algorithm requires that the length of the secret MUST be at - least 1 octet. The secret SHOULD be at least as large and - unguessable as a well-chosen password. It is preferred that the - secret be at least the length of the hash value for the hashing - algorithm chosen (16 octets for MD5). This is to ensure a - sufficiently large range for the secret to provide protection against - exhaustive search attacks. - - The one-way hash algorithm is chosen such that it is computationally - infeasible to determine the secret from the known challenge and - response values. - - The challenge value SHOULD satisfy two criteria: uniqueness and - unpredictability. Each challenge value SHOULD be unique, since - repetition of a challenge value in conjunction with the same secret - would permit an attacker to reply with a previously intercepted - response. Since it is expected that the same secret MAY be used to - authenticate with servers in disparate geographic regions, the - challenge SHOULD exhibit global and temporal uniqueness. Each - challenge value SHOULD also be unpredictable, least an attacker trick - a peer into responding to a predicted future challenge, and then use - the response to masquerade as that peer to an authenticator. - Although protocols such as CHAP are incapable of protecting against - realtime active wiretapping attacks, generation of unique - unpredictable challenges can protect against a wide range of active - attacks. - - A discussion of sources of uniqueness and probability of divergence - is included in the Magic-Number Configuration Option [1]. - -3.1. Configuration Option Format - - A summary of the Authentication-Protocol Configuration Option format - to negotiate the Challenge-Handshake Authentication Protocol is shown - below. The fields are transmitted from left to right. - - - - - - - - - -Lloyd & Simpson [Page 9] - -RFC 1334 PPP Authentication October 1992 - - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Authentication-Protocol | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Algorithm | - +-+-+-+-+-+-+-+-+ - - Type - - 3 - - Length - - 5 - - Authentication-Protocol - - c223 (hex) for Challenge-Handshake Authentication Protocol. - - Algorithm - - The Algorithm field is one octet and indicates the one-way hash - method to be used. The most up-to-date values of the CHAP - Algorithm field are specified in the most recent "Assigned - Numbers" RFC [2]. Current values are assigned as follows: - - 0-4 unused (reserved) - 5 MD5 [3] - -3.2. Packet Format - - Exactly one Challenge-Handshake Authentication Protocol packet is - encapsulated in the Information field of a PPP Data Link Layer frame - where the protocol field indicates type hex c223 (Challenge-Handshake - Authentication Protocol). A summary of the CHAP packet format is - shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data ... - +-+-+-+-+ - - - - - - -Lloyd & Simpson [Page 10] - -RFC 1334 PPP Authentication October 1992 - - - Code - - The Code field is one octet and identifies the type of CHAP - packet. CHAP Codes are assigned as follows: - - 1 Challenge - 2 Response - 3 Success - 4 Failure - - Identifier - - The Identifier field is one octet and aids in matching challenges, - responses and replies. - - Length - - The Length field is two octets and indicates the length of the - CHAP packet including the Code, Identifier, Length and Data - fields. Octets outside the range of the Length field should be - treated as Data Link Layer padding and should be ignored on - reception. - - Data - - The Data field is zero or more octets. The format of the Data - field is determined by the Code field. - -3.2.1. Challenge and Response - - Description - - The Challenge packet is used to begin the Challenge-Handshake - Authentication Protocol. The authenticator MUST transmit a CHAP - packet with the Code field set to 1 (Challenge). Additional - Challenge packets MUST be sent until a valid Response packet is - received, or an optional retry counter expires. - - A Challenge packet MAY also be transmitted at any time during the - Network-Layer Protocol phase to ensure that the connection has not - been altered. - - The peer SHOULD expect Challenge packets during the Authentication - phase and the Network-Layer Protocol phase. Whenever a Challenge - packet is received, the peer MUST transmit a CHAP packet with the - Code field set to 2 (Response). - - Whenever a Response packet is received, the authenticator compares - - - -Lloyd & Simpson [Page 11] - -RFC 1334 PPP Authentication October 1992 - - - the Response Value with its own calculation of the expected value. - Based on this comparison, the authenticator MUST send a Success or - Failure packet (described below). - - Implementation Note: Because the Success might be lost, the - authenticator MUST allow repeated Response packets after - completing the Authentication phase. To prevent discovery of - alternative Names and Secrets, any Response packets received - having the current Challenge Identifier MUST return the same - reply Code returned when the Authentication phase completed - (the message portion MAY be different). Any Response packets - received during any other phase MUST be silently discarded. - - When the Failure is lost, and the authenticator terminates the - link, the LCP Terminate-Request and Terminate-Ack provide an - alternative indication that authentication failed. - - A summary of the Challenge and Response packet format is shown below. - The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Value-Size | Value ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Name ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Code - - 1 for Challenge; - - 2 for Response. - - Identifier - - The Identifier field is one octet. The Identifier field MUST be - changed each time a Challenge is sent. - - The Response Identifier MUST be copied from the Identifier field - of the Challenge which caused the Response. - - Value-Size - - This field is one octet and indicates the length of the Value - field. - - - -Lloyd & Simpson [Page 12] - -RFC 1334 PPP Authentication October 1992 - - - Value - - The Value field is one or more octets. The most significant octet - is transmitted first. - - The Challenge Value is a variable stream of octets. The - importance of the uniqueness of the Challenge Value and its - relationship to the secret is described above. The Challenge - Value MUST be changed each time a Challenge is sent. The length - of the Challenge Value depends upon the method used to generate - the octets, and is independent of the hash algorithm used. - - The Response Value is the one-way hash calculated over a stream of - octets consisting of the Identifier, followed by (concatenated - with) the "secret", followed by (concatenated with) the Challenge - Value. The length of the Response Value depends upon the hash - algorithm used (16 octets for MD5). - - Name - - The Name field is one or more octets representing the - identification of the system transmitting the packet. There are - no limitations on the content of this field. For example, it MAY - contain ASCII character strings or globally unique identifiers in - ASN.1 syntax. The Name should not be NUL or CR/LF terminated. - The size is determined from the Length field. - - Since CHAP may be used to authenticate many different systems, the - content of the name field(s) may be used as a key to locate the - proper secret in a database of secrets. This also makes it - possible to support more than one name/secret pair per system. - -3.2.2. Success and Failure - - Description - - If the Value received in a Response is equal to the expected - value, then the implementation MUST transmit a CHAP packet with - the Code field set to 3 (Success). - - If the Value received in a Response is not equal to the expected - value, then the implementation MUST transmit a CHAP packet with - the Code field set to 4 (Failure), and SHOULD take action to - terminate the link. - - A summary of the Success and Failure packet format is shown below. - The fields are transmitted from left to right. - - - - -Lloyd & Simpson [Page 13] - -RFC 1334 PPP Authentication October 1992 - - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message ... - +-+-+-+-+-+-+-+-+-+-+-+-+- - - Code - - 3 for Success; - - 4 for Failure. - - Identifier - - The Identifier field is one octet and aids in matching requests - and replies. The Identifier field MUST be copied from the - Identifier field of the Response which caused this reply. - - Message - - The Message field is zero or more octets, and its contents are - implementation dependent. It is intended to be human readable, - and MUST NOT affect operation of the protocol. It is recommended - that the message contain displayable ASCII characters 32 through - 126 decimal. Mechanisms for extension to other character sets are - the topic of future research. The size is determined from the - Length field. - -Security Considerations - - Security issues are the primary topic of this RFC. - - The interaction of the authentication protocols within PPP are - highly implementation dependent. This is indicated by the use of - SHOULD throughout the document. - - For example, upon failure of authentication, some implementations - do not terminate the link. Instead, the implementation limits the - kind of traffic in the Network-Layer Protocols to a filtered - subset, which in turn allows the user opportunity to update - secrets or send mail to the network administrator indicating a - problem. - - There is no provision for re-tries of failed authentication. - However, the LCP state machine can renegotiate the authentication - protocol at any time, thus allowing a new attempt. It is - - - -Lloyd & Simpson [Page 14] - -RFC 1334 PPP Authentication October 1992 - - - recommended that any counters used for authentication failure not - be reset until after successful authentication, or subsequent - termination of the failed link. - - There is no requirement that authentication be full duplex or that - the same protocol be used in both directions. It is perfectly - acceptable for different protocols to be used in each direction. - This will, of course, depend on the specific protocols negotiated. - - 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). - Instead, for each named user 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 method under - different circumstances, then distinct user names SHOULD be - employed, each of which identifies exactly one authentication - method. - - Passwords and other secrets should be stored at the respective - ends such that access to them is as limited as possible. Ideally, - the secrets should only be accessible to the process requiring - access in order to perform the authentication. - - The secrets should be distributed with a mechanism that limits the - number of entities that handle (and thus gain knowledge of) the - secret. Ideally, no unauthorized person should ever gain - knowledge of the secrets. It is possible to achieve this with - SNMP Security Protocols [4], but such a mechanism is outside the - scope of this specification. - - Other distribution methods are currently undergoing research and - experimentation. The SNMP Security document also has an excellent - overview of threats to network protocols. - -References - - [1] Simpson, W., "The Point-to-Point Protocol (PPP)", RFC 1331, - Daydreamer, May 1992. - - [2] Reynolds, J., and J. Postel, "Assigned Numbers", RFC 1340, - USC/Information Sciences Institute, July 1992. - - - - - - -Lloyd & Simpson [Page 15] - -RFC 1334 PPP Authentication October 1992 - - - [3] Rivest, R., and S. Dusse, "The MD5 Message-Digest Algorithm", MIT - Laboratory for Computer Science and RSA Data Security, Inc. RFC - 1321, April 1992. - - [4] Galvin, J., McCloghrie, K., and J. Davin, "SNMP Security - Protocols", Trusted Information Systems, Inc., Hughes LAN - Systems, Inc., MIT Laboratory for Computer Science, RFC 1352, - July 1992. - -Acknowledgments - - Some of the text in this document is taken from RFC 1172, by Drew - Perkins of Carnegie Mellon University, and by Russ Hobby of the - University of California at Davis. - - Special thanks to Dave Balenson, Steve Crocker, James Galvin, and - Steve Kent, for their extensive explanations and suggestions. Now, - if only we could get them to agree with each other. - -Chair's Address - - The working group can be contacted via the current chair: - - Brian Lloyd - Lloyd & Associates - 3420 Sudbury Road - Cameron Park, California 95682 - - Phone: (916) 676-1147 - - EMail: brian@lloyd.com - -Author's Address - - Questions about this memo can also be directed to: - - William Allen Simpson - Daydreamer - Computer Systems Consulting Services - P O Box 6205 - East Lansing, MI 48826-6205 - - EMail: Bill.Simpson@um.cc.umich.edu - - - - - - - - -Lloyd & Simpson [Page 16] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1337.txt b/ext/picotcp/RFC/rfc1337.txt deleted file mode 100644 index ab09c2f..0000000 --- a/ext/picotcp/RFC/rfc1337.txt +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - -Network Working Group R. Braden -Request for Comments: 1337 ISI - May 1992 - - - TIME-WAIT Assassination Hazards in TCP - -Status of This Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard. Distribution of this memo is - unlimited. - -Abstract - - This note describes some theoretically-possible failure modes for TCP - connections and discusses possible remedies. In particular, one very - simple fix is identified. - -1. INTRODUCTION - - Experiments to validate the recently-proposed TCP extensions [RFC- - 1323] have led to the discovery of a new class of TCP failures, which - have been dubbed the "TIME-WAIT Assassination hazards". This note - describes these hazards, gives examples, and discusses possible - prevention measures. - - The failures in question all result from old duplicate segments. In - brief, the TCP mechanisms to protect against old duplicate segments - are [RFC-793]: - - (1) The 3-way handshake rejects old duplicate initial - segments, avoiding the hazard of replaying a connection. - - (2) Sequence numbers are used to reject old duplicate data and ACK - segments from the current incarnation of a given connection - (defined by a particular host and port pair). Sequence numbers - are also used to reject old duplicate segments. - - For very high-speed connections, Jacobson's PAWS ("Protect - Against Wrapped Sequences") mechanism [RFC-1323] effectively - extends the sequence numbers so wrap-around will not introduce a - hazard within the same incarnation. - - (3) There are two mechanisms to avoid hazards due to old duplicate - segments from an earlier instance of the same connection; see - the Appendix to [RFC-1185] for details. - - - - -Braden [Page 1] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - For "short and slow" connections [RFC-1185], the clock-driven - ISN (initial sequence number) selection prevents the overlap of - the sequence spaces of the old and new incarnations [RFC-793]. - (The algorithm used by Berkeley BSD TCP for stepping ISN - complicates the analysis slightly but does not change the - conclusions.) - - (4) TIME-WAIT state removes the hazard of old duplicates for "fast" - or "long" connections, in which clock-driven ISN selection is - unable to prevent overlap of the old and new sequence spaces. - The TIME-WAIT delay allows all old duplicate segments time - enough to die in the Internet before the connection is reopened. - - (5) After a system crash, the Quiet Time at system startup allows - old duplicates to disappear before any connections are opened. - - Our new observation is that (4) is unreliable: TIME-WAIT state can be - prematurely terminated ("assassinated") by an old duplicate data or - ACK segment from the current or an earlier incarnation of the same - connection. We refer to this as "TIME-WAIT Assassination" (TWA). - - Figure 1 shows an example of TIME-WAIT assassination. Segments 1-5 - are copied exactly from Figure 13 of RFC-793, showing a normal close - handshake. Packets 5.1, 5.2, and 5.3 are an extension to this - sequence, illustrating TWA. Here 5.1 is *any* old segment that is - unacceptable to TCP A. It might be unacceptable because of its - sequence number or because of an old PAWS timestamp. In either case, - TCP A sends an ACK segment 5.2 for its current SND.NXT and RCV.NXT. - Since it has no state for this connection, TCP B reflects this as RST - segment 5.3, which assassinates the TIME-WAIT state at A! - - - - - - - - - - - - - - - - - - - - - -Braden [Page 2] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - - TCP A TCP B - - 1. ESTABLISHED ESTABLISHED - - (Close) - 2. FIN-WAIT-1 --> --> CLOSE-WAIT - - 3. FIN-WAIT-2 <-- <-- CLOSE-WAIT - - (Close) - 4. TIME-WAIT <-- <-- LAST-ACK - - 5. TIME-WAIT --> --> CLOSED - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5.1. TIME-WAIT <-- ... old duplicate - - 5.2 TIME-WAIT --> --> ???? - - 5.3 CLOSED <-- <-- ???? - (prematurely) - - Figure 1. TWA Example - - - Note that TWA is not at all an unlikely event if there are any - duplicate segments that may be delayed in the network. Furthermore, - TWA cannot be prevented by PAWS timestamps; the event may happen - within the same tick of the timestamp clock. TWA is a consequence of - TCP's half-open connection discovery mechanism (see pp 33-34 of - [RFC-793]), which is designed to clean up after a system crash. - -2. The TWA Hazards - - 2.1 Introduction - - If the connection is immediately reopened after a TWA event, the - new incarnation will be exposed to old duplicate segments (except - for the initial segment, which is handled by the 3-way - handshake). There are three possible hazards that result: - - H1. Old duplicate data may be accepted erroneously. - - H2. The new connection may be de-synchronized, with the two ends - in permanent disagreement on the state. Following the spec - of RFC-793, this desynchronization results in an infinite ACK - - - -Braden [Page 3] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - loop. (It might be reasonable to change this aspect of RFC- - 793 and kill the connection instead.) - - This hazard results from acknowledging something that was not - sent. This may result from an old duplicate ACK or as a - side-effect of hazard H1. - - H3. The new connection may die. - - A duplicate segment (data or ACK) arriving in SYN-SENT state - may kill the new connection after it has apparently opened - successfully. - - Each of these hazards requires that the seqence space of the new - connection overlap to some extent with the sequence space of the - previous incarnation. As noted above, this is only possible for - "fast" or "long" connections. Since these hazards all require the - coincidence of an old duplicate falling into a particular range of - new sequence numbers, they are much less probable than TWA itself. - - TWA and the three hazards H1, H2, and H3 have been demonstrated on - a stock Sun OS 4.1.1 TCP running in an simulated environment that - massively duplicates segments. This environment is far more - hazardous than most real TCP's must cope with, and the conditions - were carefully tuned to create the necessary conditions for the - failures. However, these demonstrations are in effect an - existence proof for the hazards. - - We now present example scenarios for each of these hazards. Each - scenario is assumed to follow immediately after a TWA event - terminated the previous incarnation of the same connection. - - 2.2 HAZARD H1: Acceptance of erroneous old duplicate data. - - Without the protection of the TIME-WAIT delay, it is possible for - erroneous old duplicate data from the earlier incarnation to be - accepted. Figure 2 shows precisely how this might happen. - - - - - - - - - - - - - - -Braden [Page 4] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - - TCP A TCP B - - 1. ESTABL. --> --> ESTABL. - - 2. ESTABL. <-- <-- ESTABL. - - 3. (old dupl)... --> ESTABL. - - 4. ESTABL. <-- <-- ESTABL. - - 5. ESTABL. --> --> ESTABL. - - 6. ... <-- ESTABL. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7a. ESTABL. --> --> ESTABL. - - 8a. ESTABL. <-- ... - - 9a. ESTABL. --> --> ESTABL. - - Figure 2: Accepting Erroneous Data - - The connection has already been successfully reopened after the - assumed TWA event. Segment 1 is a normal data segment and segment - 2 is the corresponding ACK segment. Old duplicate data segment 3 - from the earlier incarnation happens to fall within the current - receive window, resulting in a duplicate ACK segment #4. The - erroneous data is queued and "lurks" in the TCP reassembly queue - until data segment 5 overlaps it. At that point, either 80 or 40 - bytes of erroneous data is delivered to the user B; the choice - depends upon the particulars of the reassembly algorithm, which - may accept the first or the last duplicate data. - - As a result, B sends segment 6, an ACK for sequence = 640, which - is 40 beyond any data sent by A. Assume for the present that this - ACK arrives at A *after* A has sent segment 7a, the next full data - segment. In that case, the ACK segment 8a acknowledges data that - has been sent, and the error goes undetected. Another possible - continuation after segment 6 leads to hazard H3, shown below. - - 2.3 HAZARD H2: De-synchronized Connection - - This hazard may result either as a side effect of H1 or directly - from an old duplicate ACK that happens to be acceptable but - acknowledges something that has not been sent. - - - -Braden [Page 5] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - Referring to Figure 2 above, suppose that the ACK generated by the - old duplicate data segment arrived before the next data segment - had been sent. The result is an infinite ACK loop, as shown by - the following alternate continuation of Figure 2. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7b. ESTABL. <-- ... - (ACK something not yet - sent => send ACK) - - 8b. ESTABL. --> --> ESTABL. - (Below window => - send ACK) - - 9b. ESTABL. <-- <-- ESTABL. - - (etc.!) - - Figure 3: Infinite ACK loop - - - 2.4 HAZARD H3: Connection Failure - - An old duplicate ACK segment may lead to an apparent refusal of - TCP A's next connection attempt, as illustrated in Figure 4. Here - indicates the TCP window field SEG.WIND.* - - TCP A TCP B - - 1. CLOSED LISTEN - - 2. SYN-SENT --> --> SYN-RCVD - - 3. ... <-- SYN-RCVD - - 4. SYN-SENT <-- ... (old duplicate) - - 5. SYN-SENT --> --> LISTEN - - 6. ESTABLISHED <-- ... - - 7. ESTABLISHED --> --> LISTEN - - 8. CLOSED <-- <-- LISTEN - - - Figure 4: Connection Failure from Old Duplicate - - - - -Braden [Page 6] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - The key to the failure in Figure 4 is that the RST segment 5 is - acceptable to TCP B in SYN-RECEIVED state, because the sequence - space of the earlier connection that produced this old duplicate - overlaps the new connection space. Thus, in segment #5 - falls within TCP B's receive window [101,900). In experiments, - this failure mode was very easy to demonstrate. (Kurt Matthys has - pointed out that this scenario is time-dependent: if TCP A should - timeout and retransmit the initial SYN after segment 5 arrives and - before segment 6, then the open will complete successfully.) - -3. Fixes for TWA Hazards - - We discuss three possible fixes to TCP to avoid these hazards. - - (F1) Ignore RST segments in TIME-WAIT state. - - If the 2 minute MSL is enforced, this fix avoids all three - hazards. - - This is the simplest fix. One could also argue that it is - formally the correct thing to do; since allowing time for old - duplicate segments to die is one of TIME-WAIT state's functions, - the state should not be truncated by a RST segment. - - (F2) Use PAWS to avoid the hazards. - - Suppose that the TCP ignores RST segments in TIME-WAIT state, - but only long enough to guarantee that the timestamp clocks on - both ends have ticked. Then the PAWS mechanism [RFC-1323] will - prevent old duplicate data segments from interfering with the - new incarnation, eliminating hazard H1. For reasons explained - below, however, it may not eliminate all old duplicate ACK - segments, so hazards H2 and H3 will still exist. - - In the language of the TCP Extensions RFC [RFC-1323]: - - When processing a RST bit in TIME-WAIT state: - - If (Snd.TS.OK is off) or (Time.in.TW.state() >= W) - then enter the CLOSED state, delete the TCB, - drop the RST segment, and return. - - else simply drop the RST segment and return. - - Here "Time.in.TW.state()" is a function returning the elapsed - time since TIME-WAIT state was entered, and W is a constant that - is at least twice the longest possible period for timestamp - clocks, i.e., W = 2 secs [RFC-1323]. - - - -Braden [Page 7] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - This assumes that the timestamp clock at each end continues to - advance at a constant rate whether or not there are any open - connections. We do not have to consider what happens across a - system crash (e.g., the timestamp clock may jump randomly), - because of the assumed Quiet Time at system startup. - - Once this change is in place, the initial timestamps that occur - on the SYN and {SYN,ACK} segments reopening the connection will - be larger than any timestamp on a segment from earlier - incarnations. As a result, the PAWS mechanism operating in the - new connection incarnation will avoid the H1 hazard, ie. - acceptance of old duplicate data. - - The effectiveness of fix (F2) in preventing acceptance of old - duplicate data segments, i.e., hazard H1, has been demonstrated - in the Sun OS TCP mentioned earlier. Unfortunately, these tests - revealed a somewhat surprising fact: old duplicate ACKs from - the earlier incarnation can still slip past PAWS, so that (F2) - will not prevent failures H2 or H3. What happens is that TIME- - WAIT state effectively regenerates the timestamp of an old - duplicate ACK. That is, when an old duplicate arrives in TIME- - WAIT state, an extended TCP will send out its own ACK with a - timestamp option containing its CURRENT timestamp clock value. - If this happens immediately before the TWA mechanism kills - TIME-WAIT state, the result will be a "new old duplicate" - segment with a current timestamp that may pass the PAWS test on - the reopened connection. - - Whether H2 and H3 are critical depends upon how often they - happen and what assumptions the applications make about TCP - semantics. In the case of the H3 hazard, merely trying the open - again is likely to succeed. Furthermore, many production TCPs - have (despite the advice of the researchers who developed TCP) - incorporated a "keep-alive" mechanism, which may kill - connections unnecessarily. The frequency of occurrence of H2 - and H3 may well be much lower than keep-alive failures or - transient internet routing failures. - - (F3) Use 64-bit Sequence Numbers - - O'Malley and Peterson [RFC-1264] have suggested expansion of the - TCP sequence space to 64 bits as an alternative to PAWS for - avoiding the hazard of wrapped sequence numbers within the same - incarnation. It is worthwhile to inquire whether 64-bit - sequence numbers could be used to avoid the TWA hazards as well. - - Using 64 bit sequence numbers would not prevent TWA - the early - termination of TIME-WAIT state. However, it appears that a - - - -Braden [Page 8] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - combination of 64-bit sequence numbers with an appropriate - modification of the TCP parameters could defeat all of the TWA - hazards H1, H2, and H3. The basis for this is explained in an - appendix to this memo. In summary, it could be arranged that - the same sequence space would be reused only after a very long - period of time, so every connection would be "slow" and "short". - -4. Conclusions - - Of the three fixes described in the previous section, fix (F1), - ignoring RST segments in TIME-WAIT state, seems like the best short- - term solution. It is certainly the simplest. It would be very - desirable to do an extended test of this change in a production - environment, to ensure there is no unexpected bad effect of ignoring - RSTs in TIME-WAIT state. - - Fix (F2) is more complex and is at best a partial fix. (F3), using - 64-bit sequence numbers, would be a significant change in the - protocol, and its implications need to be thoroughly understood. - (F3) may turn out to be a long-term fix for the hazards discussed in - this note. - -APPENDIX: Using 64-bit Sequence Numbers - - This appendix provides a justification of our statement that 64-bit - sequence numbers could prevent the TWA hazards. - - The theoretical ISN calculation used by TCP is: - - ISN = (R*T) mod 2**n. - - where T is the real time in seconds (from an arbitrary origin, fixed - when the system is started), R is a constant, currently 250 KBps, and - n = 32 is the size of the sequence number field. - - The limitations of current TCP are established by n, R, and the - maximum segment lifetime MSL = 4 minutes. The shortest time Twrap to - wrap the sequence space is: - - Twrap = (2**n)/r - - where r is the maximum transfer rate. To avoid old duplicate - segments in the same connection, we require that Twrap > MSL (in - practice, we need Twrap >> MSL). - - - - - - - -Braden [Page 9] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - The clock-driven ISN numbers wrap in time TwrapISN: - - TwrapISN = (2**n)/R - - For current TCP, TwrapISN = 4.55 hours. - - The cases for old duplicates from previous connections can be divided - into four regions along two dimensions: - - * Slow vs. fast connections, corresponding to r < R or r >= R. - - * Short vs. long connections, corresponding to duration E < - TwrapISN or E >= TwrapISN. - - On short slow connections, the clock-driven ISN selection rejects old - duplicates. For all other cases, the TIME-WAIT delay of 2*MSL is - required so old duplicates can expire before they infect a new - incarnation. This is discussed in detail in the Appendix to [RFC- - 1185]. - - With this background, we can consider the effect of increasing n to - 64. We would like to increase both R and TwrapISN far enough that - all connections will be short and slow, i.e., so that the clock- - driven ISN selection will reject all old duplicates. Put another - way, we want to every connection to have a unique chunk of the - seqence space. For this purpose, we need R larger than the maximum - foreseeable rate r, and TwrapISN greater than the longest foreseeable - connection duration E. - - In fact, this appears feasible with n = 64 bits. Suppose that we use - R = 2**33 Bps; this is approximately 8 gigabytes per second, a - reasonable upper limit on throughput of a single TCP connection. - Then TwrapISN = 68 years, a reasonable upper limit on TCP connection - duration. Note that this particular choice of R corresponds to - incrementing the ISN by 2**32 every 0.5 seconds, as would happen with - the Berkeley BSD implementation of TCP. Then the low-order 32 bits - of a 64-bit ISN would always be exactly zero. - - REFERENCES - - [RFC-793] Postel, J., "Transmission Control Protocol", RFC-793, - USC/Information Sciences Institute, September 1981. - - [RFC-1185] Jacobson, V., Braden, R., and Zhang, L., "TCP - Extension for High-Speed Paths", RFC-1185, Lawrence Berkeley Labs, - USC/Information Sciences Institute, and Xerox Palo Alto Research - Center, October 1990. - - - - -Braden [Page 10] - -RFC 1337 TCP TIME-WAIT Hazards May 1992 - - - [RFC-1263] O'Malley, S. and L. Peterson, "TCP Extensions - Considered Harmful", RFC-1263, University of Arizona, October - 1991. - - [RFC-1323] Jacobson, V., Braden, R. and D. Borman "TCP Extensions - for High Performance", RFC-1323, Lawrence Berkeley Labs, - USC/Information Sciences Institute, and Cray Research, May 1992. - -Security Considerations - - Security issues are not discussed in this memo. - -Author's Address: - - Bob Braden - University of Southern California - Information Sciences Institute - 4676 Admiralty Way - Marina del Rey, CA 90292 - - Phone: (213) 822-1511 - EMail: Braden@ISI.EDU - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Braden [Page 11] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1350.txt b/ext/picotcp/RFC/rfc1350.txt deleted file mode 100644 index e00113b..0000000 --- a/ext/picotcp/RFC/rfc1350.txt +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - -Network Working Group K. Sollins -Request For Comments: 1350 MIT -STD: 33 July 1992 -Obsoletes: RFC 783 - - - THE TFTP PROTOCOL (REVISION 2) - -Status of this Memo - - This RFC specifies an IAB standards track protocol for the Internet - community, and requests discussion and suggestions for improvements. - Please refer to the current edition of the "IAB Official Protocol - Standards" for the standardization state and status of this protocol. - Distribution of this memo is unlimited. - -Summary - - TFTP is a very simple protocol used to transfer files. It is from - this that its name comes, Trivial File Transfer Protocol or TFTP. - Each nonterminal packet is acknowledged separately. This document - describes the protocol and its types of packets. The document also - explains the reasons behind some of the design decisions. - -Acknowlegements - - The protocol was originally designed by Noel Chiappa, and was - redesigned by him, Bob Baldwin and Dave Clark, with comments from - Steve Szymanski. The current revision of the document includes - modifications stemming from discussions with and suggestions from - Larry Allen, Noel Chiappa, Dave Clark, Geoff Cooper, Mike Greenwald, - Liza Martin, David Reed, Craig Milo Rogers (of USC-ISI), Kathy - Yellick, and the author. The acknowledgement and retransmission - scheme was inspired by TCP, and the error mechanism was suggested by - PARC's EFTP abort message. - - The May, 1992 revision to fix the "Sorcerer's Apprentice" protocol - bug [4] and other minor document problems was done by Noel Chiappa. - - This research was supported by the Advanced Research Projects Agency - of the Department of Defense and was monitored by the Office of Naval - Research under contract number N00014-75-C-0661. - -1. Purpose - - TFTP is a simple protocol to transfer files, and therefore was named - the Trivial File Transfer Protocol or TFTP. It has been implemented - on top of the Internet User Datagram protocol (UDP or Datagram) [2] - - - -Sollins [Page 1] - -RFC 1350 TFTP Revision 2 July 1992 - - - so it may be used to move files between machines on different - networks implementing UDP. (This should not exclude the possibility - of implementing TFTP on top of other datagram protocols.) It is - designed to be small and easy to implement. Therefore, it lacks most - of the features of a regular FTP. The only thing it can do is read - and write files (or mail) from/to a remote server. It cannot list - directories, and currently has no provisions for user authentication. - In common with other Internet protocols, it passes 8 bit bytes of - data. - - Three modes of transfer are currently supported: netascii (This is - ascii as defined in "USA Standard Code for Information Interchange" - [1] with the modifications specified in "Telnet Protocol - Specification" [3].) Note that it is 8 bit ascii. The term - "netascii" will be used throughout this document to mean this - particular version of ascii.); octet (This replaces the "binary" mode - of previous versions of this document.) raw 8 bit bytes; mail, - netascii characters sent to a user rather than a file. (The mail - mode is obsolete and should not be implemented or used.) Additional - modes can be defined by pairs of cooperating hosts. - - Reference [4] (section 4.2) should be consulted for further valuable - directives and suggestions on TFTP. - -2. Overview of the Protocol - - Any transfer begins with a request to read or write a file, which - also serves to request a connection. If the server grants the - request, the connection is opened and the file is sent in fixed - length blocks of 512 bytes. Each data packet contains one block of - data, and must be acknowledged by an acknowledgment packet before the - next packet can be sent. A data packet of less than 512 bytes - signals termination of a transfer. If a packet gets lost in the - network, the intended recipient will timeout and may retransmit his - last packet (which may be data or an acknowledgment), thus causing - the sender of the lost packet to retransmit that lost packet. The - sender has to keep just one packet on hand for retransmission, since - the lock step acknowledgment guarantees that all older packets have - been received. Notice that both machines involved in a transfer are - considered senders and receivers. One sends data and receives - acknowledgments, the other sends acknowledgments and receives data. - - Most errors cause termination of the connection. An error is - signalled by sending an error packet. This packet is not - acknowledged, and not retransmitted (i.e., a TFTP server or user may - terminate after sending an error message), so the other end of the - connection may not get it. Therefore timeouts are used to detect - such a termination when the error packet has been lost. Errors are - - - -Sollins [Page 2] - -RFC 1350 TFTP Revision 2 July 1992 - - - caused by three types of events: not being able to satisfy the - request (e.g., file not found, access violation, or no such user), - receiving a packet which cannot be explained by a delay or - duplication in the network (e.g., an incorrectly formed packet), and - losing access to a necessary resource (e.g., disk full or access - denied during a transfer). - - TFTP recognizes only one error condition that does not cause - termination, the source port of a received packet being incorrect. - In this case, an error packet is sent to the originating host. - - This protocol is very restrictive, in order to simplify - implementation. For example, the fixed length blocks make allocation - straight forward, and the lock step acknowledgement provides flow - control and eliminates the need to reorder incoming data packets. - -3. Relation to other Protocols - - As mentioned TFTP is designed to be implemented on top of the - Datagram protocol (UDP). Since Datagram is implemented on the - Internet protocol, packets will have an Internet header, a Datagram - header, and a TFTP header. Additionally, the packets may have a - header (LNI, ARPA header, etc.) to allow them through the local - transport medium. As shown in Figure 3-1, the order of the contents - of a packet will be: local medium header, if used, Internet header, - Datagram header, TFTP header, followed by the remainder of the TFTP - packet. (This may or may not be data depending on the type of packet - as specified in the TFTP header.) TFTP does not specify any of the - values in the Internet header. On the other hand, the source and - destination port fields of the Datagram header (its format is given - in the appendix) are used by TFTP and the length field reflects the - size of the TFTP packet. The transfer identifiers (TID's) used by - TFTP are passed to the Datagram layer to be used as ports; therefore - they must be between 0 and 65,535. The initialization of TID's is - discussed in the section on initial connection protocol. - - The TFTP header consists of a 2 byte opcode field which indicates - the packet's type (e.g., DATA, ERROR, etc.) These opcodes and the - formats of the various types of packets are discussed further in the - section on TFTP packets. - - - - - - - - - - - -Sollins [Page 3] - -RFC 1350 TFTP Revision 2 July 1992 - - - --------------------------------------------------- - | Local Medium | Internet | Datagram | TFTP | - --------------------------------------------------- - - Figure 3-1: Order of Headers - - -4. Initial Connection Protocol - - A transfer is established by sending a request (WRQ to write onto a - foreign file system, or RRQ to read from it), and receiving a - positive reply, an acknowledgment packet for write, or the first data - packet for read. In general an acknowledgment packet will contain - the block number of the data packet being acknowledged. Each data - packet has associated with it a block number; block numbers are - consecutive and begin with one. Since the positive response to a - write request is an acknowledgment packet, in this special case the - block number will be zero. (Normally, since an acknowledgment packet - is acknowledging a data packet, the acknowledgment packet will - contain the block number of the data packet being acknowledged.) If - the reply is an error packet, then the request has been denied. - - In order to create a connection, each end of the connection chooses a - TID for itself, to be used for the duration of that connection. The - TID's chosen for a connection should be randomly chosen, so that the - probability that the same number is chosen twice in immediate - succession is very low. Every packet has associated with it the two - TID's of the ends of the connection, the source TID and the - destination TID. These TID's are handed to the supporting UDP (or - other datagram protocol) as the source and destination ports. A - requesting host chooses its source TID as described above, and sends - its initial request to the known TID 69 decimal (105 octal) on the - serving host. The response to the request, under normal operation, - uses a TID chosen by the server as its source TID and the TID chosen - for the previous message by the requestor as its destination TID. - The two chosen TID's are then used for the remainder of the transfer. - - As an example, the following shows the steps used to establish a - connection to write a file. Note that WRQ, ACK, and DATA are the - names of the write request, acknowledgment, and data types of packets - respectively. The appendix contains a similar example for reading a - file. - - - - - - - - - -Sollins [Page 4] - -RFC 1350 TFTP Revision 2 July 1992 - - - 1. Host A sends a "WRQ" to host B with source= A's TID, - destination= 69. - - 2. Host B sends a "ACK" (with block number= 0) to host A with - source= B's TID, destination= A's TID. - - At this point the connection has been established and the first data - packet can be sent by Host A with a sequence number of 1. In the - next step, and in all succeeding steps, the hosts should make sure - that the source TID matches the value that was agreed on in steps 1 - and 2. If a source TID does not match, the packet should be - discarded as erroneously sent from somewhere else. An error packet - should be sent to the source of the incorrect packet, while not - disturbing the transfer. This can be done only if the TFTP in fact - receives a packet with an incorrect TID. If the supporting protocols - do not allow it, this particular error condition will not arise. - - The following example demonstrates a correct operation of the - protocol in which the above situation can occur. Host A sends a - request to host B. Somewhere in the network, the request packet is - duplicated, and as a result two acknowledgments are returned to host - A, with different TID's chosen on host B in response to the two - requests. When the first response arrives, host A continues the - connection. When the second response to the request arrives, it - should be rejected, but there is no reason to terminate the first - connection. Therefore, if different TID's are chosen for the two - connections on host B and host A checks the source TID's of the - messages it receives, the first connection can be maintained while - the second is rejected by returning an error packet. - -5. TFTP Packets - - TFTP supports five types of packets, all of which have been mentioned - above: - - opcode operation - 1 Read request (RRQ) - 2 Write request (WRQ) - 3 Data (DATA) - 4 Acknowledgment (ACK) - 5 Error (ERROR) - - The TFTP header of a packet contains the opcode associated with - that packet. - - - - - - - -Sollins [Page 5] - -RFC 1350 TFTP Revision 2 July 1992 - - - 2 bytes string 1 byte string 1 byte - ------------------------------------------------ - | Opcode | Filename | 0 | Mode | 0 | - ------------------------------------------------ - - Figure 5-1: RRQ/WRQ packet - - - RRQ and WRQ packets (opcodes 1 and 2 respectively) have the format - shown in Figure 5-1. The file name is a sequence of bytes in - netascii terminated by a zero byte. The mode field contains the - string "netascii", "octet", or "mail" (or any combination of upper - and lower case, such as "NETASCII", NetAscii", etc.) in netascii - indicating the three modes defined in the protocol. A host which - receives netascii mode data must translate the data to its own - format. Octet mode is used to transfer a file that is in the 8-bit - format of the machine from which the file is being transferred. It - is assumed that each type of machine has a single 8-bit format that - is more common, and that that format is chosen. For example, on a - DEC-20, a 36 bit machine, this is four 8-bit bytes to a word with - four bits of breakage. If a host receives a octet file and then - returns it, the returned file must be identical to the original. - Mail mode uses the name of a mail recipient in place of a file and - must begin with a WRQ. Otherwise it is identical to netascii mode. - The mail recipient string should be of the form "username" or - "username@hostname". If the second form is used, it allows the - option of mail forwarding by a relay computer. - - The discussion above assumes that both the sender and recipient are - operating in the same mode, but there is no reason that this has to - be the case. For example, one might build a storage server. There - is no reason that such a machine needs to translate netascii into its - own form of text. Rather, the sender might send files in netascii, - but the storage server might simply store them without translation in - 8-bit format. Another such situation is a problem that currently - exists on DEC-20 systems. Neither netascii nor octet accesses all - the bits in a word. One might create a special mode for such a - machine which read all the bits in a word, but in which the receiver - stored the information in 8-bit format. When such a file is - retrieved from the storage site, it must be restored to its original - form to be useful, so the reverse mode must also be implemented. The - user site will have to remember some information to achieve this. In - both of these examples, the request packets would specify octet mode - to the foreign host, but the local host would be in some other mode. - No such machine or application specific modes have been specified in - TFTP, but one would be compatible with this specification. - - It is also possible to define other modes for cooperating pairs of - - - -Sollins [Page 6] - -RFC 1350 TFTP Revision 2 July 1992 - - - hosts, although this must be done with care. There is no requirement - that any other hosts implement these. There is no central authority - that will define these modes or assign them names. - - - 2 bytes 2 bytes n bytes - ---------------------------------- - | Opcode | Block # | Data | - ---------------------------------- - - Figure 5-2: DATA packet - - - Data is actually transferred in DATA packets depicted in Figure 5-2. - DATA packets (opcode = 3) have a block number and data field. The - block numbers on data packets begin with one and increase by one for - each new block of data. This restriction allows the program to use a - single number to discriminate between new packets and duplicates. - The data field is from zero to 512 bytes long. If it is 512 bytes - long, the block is not the last block of data; if it is from zero to - 511 bytes long, it signals the end of the transfer. (See the section - on Normal Termination for details.) - - All packets other than duplicate ACK's and those used for - termination are acknowledged unless a timeout occurs [4]. Sending a - DATA packet is an acknowledgment for the first ACK packet of the - previous DATA packet. The WRQ and DATA packets are acknowledged by - ACK or ERROR packets, while RRQ - - - 2 bytes 2 bytes - --------------------- - | Opcode | Block # | - --------------------- - - Figure 5-3: ACK packet - - - and ACK packets are acknowledged by DATA or ERROR packets. Figure - 5-3 depicts an ACK packet; the opcode is 4. The block number in - an ACK echoes the block number of the DATA packet being - acknowledged. A WRQ is acknowledged with an ACK packet having a - block number of zero. - - - - - - - - -Sollins [Page 7] - -RFC 1350 TFTP Revision 2 July 1992 - - - 2 bytes 2 bytes string 1 byte - ----------------------------------------- - | Opcode | ErrorCode | ErrMsg | 0 | - ----------------------------------------- - - Figure 5-4: ERROR packet - - - An ERROR packet (opcode 5) takes the form depicted in Figure 5-4. An - ERROR packet can be the acknowledgment of any other type of packet. - The error code is an integer indicating the nature of the error. A - table of values and meanings is given in the appendix. (Note that - several error codes have been added to this version of this - document.) The error message is intended for human consumption, and - should be in netascii. Like all other strings, it is terminated with - a zero byte. - -6. Normal Termination - - The end of a transfer is marked by a DATA packet that contains - between 0 and 511 bytes of data (i.e., Datagram length < 516). This - packet is acknowledged by an ACK packet like all other DATA packets. - The host acknowledging the final DATA packet may terminate its side - of the connection on sending the final ACK. On the other hand, - dallying is encouraged. This means that the host sending the final - ACK will wait for a while before terminating in order to retransmit - the final ACK if it has been lost. The acknowledger will know that - the ACK has been lost if it receives the final DATA packet again. - The host sending the last DATA must retransmit it until the packet is - acknowledged or the sending host times out. If the response is an - ACK, the transmission was completed successfully. If the sender of - the data times out and is not prepared to retransmit any more, the - transfer may still have been completed successfully, after which the - acknowledger or network may have experienced a problem. It is also - possible in this case that the transfer was unsuccessful. In any - case, the connection has been closed. - -7. Premature Termination - - If a request can not be granted, or some error occurs during the - transfer, then an ERROR packet (opcode 5) is sent. This is only a - courtesy since it will not be retransmitted or acknowledged, so it - may never be received. Timeouts must also be used to detect errors. - - - - - - - - -Sollins [Page 8] - -RFC 1350 TFTP Revision 2 July 1992 - - -I. Appendix - -Order of Headers - - 2 bytes - ---------------------------------------------------------- - | Local Medium | Internet | Datagram | TFTP Opcode | - ---------------------------------------------------------- - -TFTP Formats - - Type Op # Format without header - - 2 bytes string 1 byte string 1 byte - ----------------------------------------------- - RRQ/ | 01/02 | Filename | 0 | Mode | 0 | - WRQ ----------------------------------------------- - 2 bytes 2 bytes n bytes - --------------------------------- - DATA | 03 | Block # | Data | - --------------------------------- - 2 bytes 2 bytes - ------------------- - ACK | 04 | Block # | - -------------------- - 2 bytes 2 bytes string 1 byte - ---------------------------------------- - ERROR | 05 | ErrorCode | ErrMsg | 0 | - ---------------------------------------- - -Initial Connection Protocol for reading a file - - 1. Host A sends a "RRQ" to host B with source= A's TID, - destination= 69. - - 2. Host B sends a "DATA" (with block number= 1) to host A with - source= B's TID, destination= A's TID. - - - - - - - - - - - - - - -Sollins [Page 9] - -RFC 1350 TFTP Revision 2 July 1992 - - -Error Codes - - Value Meaning - - 0 Not defined, see error message (if any). - 1 File not found. - 2 Access violation. - 3 Disk full or allocation exceeded. - 4 Illegal TFTP operation. - 5 Unknown transfer ID. - 6 File already exists. - 7 No such user. - -Internet User Datagram Header [2] - - (This has been included only for convenience. TFTP need not be - implemented on top of the Internet User Datagram Protocol.) - - Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Length | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - Values of Fields - - - Source Port Picked by originator of packet. - - Dest. Port Picked by destination machine (69 for RRQ or WRQ). - - Length Number of bytes in UDP packet, including UDP header. - - Checksum Reference 2 describes rules for computing checksum. - (The implementor of this should be sure that the - correct algorithm is used here.) - Field contains zero if unused. - - Note: TFTP passes transfer identifiers (TID's) to the Internet User - Datagram protocol to be used as the source and destination ports. - - - - - - -Sollins [Page 10] - -RFC 1350 TFTP Revision 2 July 1992 - - -References - - [1] USA Standard Code for Information Interchange, USASI X3.4-1968. - - [2] Postel, J., "User Datagram Protocol," RFC 768, USC/Information - Sciences Institute, 28 August 1980. - - [3] Postel, J., "Telnet Protocol Specification," RFC 764, - USC/Information Sciences Institute, June, 1980. - - [4] Braden, R., Editor, "Requirements for Internet Hosts -- - Application and Support", RFC 1123, USC/Information Sciences - Institute, October 1989. - -Security Considerations - - Since TFTP includes no login or access control mechanisms, care must - be taken in the rights granted to a TFTP server process so as not to - violate the security of the server hosts file system. TFTP is often - installed with controls such that only files that have public read - access are available via TFTP and writing files via TFTP is - disallowed. - -Author's Address - - Karen R. Sollins - Massachusetts Institute of Technology - Laboratory for Computer Science - 545 Technology Square - Cambridge, MA 02139-1986 - - Phone: (617) 253-6006 - - EMail: SOLLINS@LCS.MIT.EDU - - - - - - - - - - - - - - - - - -Sollins [Page 11] - \ No newline at end of file diff --git a/ext/picotcp/RFC/rfc1624.txt b/ext/picotcp/RFC/rfc1624.txt deleted file mode 100644 index fe9fc01..0000000 --- a/ext/picotcp/RFC/rfc1624.txt +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - -Network Working Group A. Rijsinghani, Editor -Request for Comments: 1624 Digital Equipment Corporation -Updates: 1141 May 1994 -Category: Informational - - - Computation of the Internet Checksum - via Incremental Update - -Status of this Memo - - This memo provides information for the Internet community. This memo - does not specify an Internet standard of any kind. Distribution of - this memo is unlimited. - -Abstract - - This memo describes an updated technique for incremental computation - of the standard Internet checksum. It updates the method described - in RFC 1141. - -Table of Contents - - 1. Introduction .......................................... 1 - 2. Notation and Equations ................................ 2 - 3. Discussion ............................................ 2 - 4. Examples .............................................. 3 - 5. Checksum verification by end systems .................. 4 - 6. Historical Note ....................................... 4 - 7. Acknowledgments ....................................... 5 - 8. Security Considerations ............................... 5 - 9. Conclusions ........................................... 5 - 10. Author's Address ..................................... 5 - 11. References ........................................... 6 - -1. Introduction - - Incremental checksum update is useful in speeding up several - types of operations routinely performed on IP packets, such as - TTL update, IP fragmentation, and source route update. - - RFC 1071, on pages 4 and 5, describes a procedure to - incrementally update the standard Internet checksum. The - relevant discussion, though comprehensive, was not complete. - Therefore, RFC 1141 was published to replace this description - on Incremental Update. In particular, RFC 1141 provides a - more detailed exposure to the procedure described in RFC 1071. - However, it computes a result for certain cases that differs - - - -Rijsinghani [Page 1] - -RFC 1624 Incremental Internet Checksum May 1994 - - - from the one obtained from scratch (one's complement of one's - complement sum of the original fields). - - For the sake of completeness, this memo briefly highlights key - points from RFCs 1071 and 1141. Based on these discussions, - an updated procedure to incrementally compute the standard - Internet checksum is developed and presented. - -2. Notation and Equations - - Given the following notation: - - HC - old checksum in header - C - one's complement sum of old header - HC' - new checksum in header - C' - one's complement sum of new header - m - old value of a 16-bit field - m' - new value of a 16-bit field - - RFC 1071 states that C' is: - - C' = C + (-m) + m' -- [Eqn. 1] - = C + (m' - m) - - As RFC 1141 points out, the equation above is not useful for direct - use in incremental updates since C and C' do not refer to the actual - checksum stored in the header. In addition, it is pointed out that - RFC 1071 did not specify that all arithmetic must be performed using - one's complement arithmetic. - - Finally, complementing the above equation to get the actual checksum, - RFC 1141 presents the following: - - HC' = ~(C + (-m) + m') - = HC + (m - m') - = HC + m + ~m' -- [Eqn. 2] - -3. Discussion - - Although this equation appears to work, there are boundary conditions - under which it produces a result which differs from the one obtained - by checksum computation from scratch. This is due to the way zero is - handled in one's complement arithmetic. - - In one's complement, there are two representations of zero: the all - zero and the all one bit values, often referred to as +0 and -0. - One's complement addition of non-zero inputs can produce -0 as a - result, but never +0. Since there is guaranteed to be at least one - - - -Rijsinghani [Page 2] - -RFC 1624 Incremental Internet Checksum May 1994 - - - non-zero field in the IP header, and the checksum field in the - protocol header is the complement of the sum, the checksum field can - never contain ~(+0), which is -0 (0xFFFF). It can, however, contain - ~(-0), which is +0 (0x0000). - - RFC 1141 yields an updated header checksum of -0 when it should be - +0. This is because it assumed that one's complement has a - distributive property, which does not hold when the result is 0 (see - derivation of [Eqn. 2]). - - The problem is avoided by not assuming this property. The correct - equation is given below: - - HC' = ~(C + (-m) + m') -- [Eqn. 3] - = ~(~HC + ~m + m') - -4. Examples - - Consider an IP packet header in which a 16-bit field m = 0x5555 - changes to m' = 0x3285. Also, the one's complement sum of all other - header octets is 0xCD7A. - - Then the header checksum would be: - - HC = ~(0xCD7A + 0x5555) - = ~0x22D0 - = 0xDD2F - - The new checksum via recomputation is: - - HC' = ~(0xCD7A + 0x3285) - = ~0xFFFF - = 0x0000 - - Using [Eqn. 2], as specified in RFC 1141, the new checksum is - computed as: - - HC' = HC + m + ~m' - = 0xDD2F + 0x5555 + ~0x3285 - = 0xFFFF - - which does not match that computed from scratch, and moreover can - never obtain for an IP header. - - - - - - - - -Rijsinghani [Page 3] - -RFC 1624 Incremental Internet Checksum May 1994 - - - Applying [Eqn. 3] to the example above, we get the correct result: - - HC' = ~(C + (-m) + m') - = ~(0x22D0 + ~0x5555 + 0x3285) - = ~0xFFFF - = 0x0000 - -5. Checksum verification by end systems - - If an end system verifies the checksum by including the checksum - field itself in the one's complement sum and then comparing the - result against -0, as recommended by RFC 1071, it does not matter if - an intermediate system generated a -0 instead of +0 due to the RFC - 1141 property described here. In the example above: - - 0xCD7A + 0x3285 + 0xFFFF = 0xFFFF - 0xCD7A + 0x3285 + 0x0000 = 0xFFFF - - However, implementations exist which verify the checksum by computing - it and comparing against the header checksum field. - - It is recommended that intermediate systems compute incremental - checksum using the method described in this document, and end systems - verify checksum as per the method described in RFC 1071. - - The method in [Eqn. 3] is slightly more expensive than the one in RFC - 1141. If this is a concern, the two additional instructions can be - eliminated by subtracting complements with borrow [see Sec. 7]. This - would result in the following equation: - - HC' = HC - ~m - m' -- [Eqn. 4] - - In the example shown above, - - HC' = HC - ~m - m' - = 0xDD2F - ~0x5555 - 0x3285 - = 0x0000 - -6. Historical Note - - A historical aside: the fact that standard one's complement - arithmetic produces negative zero results is one of its main - drawbacks; it makes for difficulty in interpretation. In the CDC - 6000 series computers [4], this problem was avoided by using - subtraction as the primitive in one's complement arithmetic (i.e., - addition is subtraction of the complement). - - - - - -Rijsinghani [Page 4] - -RFC 1624 Incremental Internet Checksum May 1994 - - -7. Acknowledgments - - The contribution of the following individuals to the work that led to - this document is acknowledged: - - Manu Kaycee - Ascom Timeplex, Incorporated - Paul Koning - Digital Equipment Corporation - Tracy Mallory - 3Com Corporation - Krishna Narayanaswamy - Digital Equipment Corporation - Atul Pandya - Digital Equipment Corporation - - The failure condition was uncovered as a result of IP testing on a - product which implemented the RFC 1141 algorithm. It was analyzed, - and the updated algorithm devised. This algorithm was also verified - using simulation. It was also shown that the failure condition - disappears if the checksum verification is done as per RFC 1071. - -8. Security Considerations - - Security issues are not discussed in this memo. - -9. Conclusions - - It is recommended that either [Eqn. 3] or [Eqn. 4] be the - implementation technique used for incremental update of the standard - Internet checksum. - -10. Author's Address - - Anil Rijsinghani - Digital Equipment Corporation - 550 King St - Littleton, MA 01460 - - Phone: (508) 486-6786 - EMail: anil@levers.enet.dec.com - - - - - - - - - - - - - - - -Rijsinghani [Page 5] - -RFC 1624 Incremental Internet Checksum May 1994 - - -11. References - - [1] Postel, J., "Internet Protocol - DARPA Internet Program Protocol - Specification", STD 5, RFC 791, DARPA, September 1981. - - [2] Braden, R., Borman, D., and C. Partridge, "Computing the Internet - Checksum", RFC 1071, ISI, Cray Research, BBN Laboratories, - September 1988. - - [3] Mallory, T., and A. Kullberg, "Incremental Updating of the - Internet Checksum", RFC 1141, BBN Communications, January 1990. - - [4] Thornton, J., "Design of a Computer -- the Control - Data 6600", Scott, Foresman and Company, 1970. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Rijsinghani [Page 6] - diff --git a/ext/picotcp/RFC/rfc1662.txt b/ext/picotcp/RFC/rfc1662.txt deleted file mode 100644 index 18b7c24..0000000 --- a/ext/picotcp/RFC/rfc1662.txt +++ /dev/null @@ -1,1440 +0,0 @@ - - - - - - -Network Working Group W. Simpson, Editor -Request for Comments: 1662 Daydreamer -STD: 51 July 1994 -Obsoletes: 1549 -Category: Standards Track - - - PPP in HDLC-like Framing - - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - - -Abstract - - The Point-to-Point Protocol (PPP) [1] provides a standard method for - transporting multi-protocol datagrams over point-to-point links. - - This document describes the use of HDLC-like framing for PPP - encapsulated packets. - - -Table of Contents - - - 1. Introduction .......................................... 1 - 1.1 Specification of Requirements ................... 2 - 1.2 Terminology ..................................... 2 - - 2. Physical Layer Requirements ........................... 3 - - 3. The Data Link Layer ................................... 4 - 3.1 Frame Format .................................... 5 - 3.2 Modification of the Basic Frame ................. 7 - - 4. Octet-stuffed framing ................................. 8 - 4.1 Flag Sequence ................................... 8 - 4.2 Transparency .................................... 8 - 4.3 Invalid Frames .................................. 9 - 4.4 Time Fill ....................................... 9 - 4.4.1 Octet-synchronous ............................... 9 - 4.4.2 Asynchronous .................................... 9 - 4.5 Transmission Considerations ..................... 10 - 4.5.1 Octet-synchronous ............................... 10 - 4.5.2 Asynchronous .................................... 10 - - -Simpson [Page i] - RFC 1662 HDLC-like Framing July 1994 - - - 5. Bit-stuffed framing ................................... 11 - 5.1 Flag Sequence ................................... 11 - 5.2 Transparency .................................... 11 - 5.3 Invalid Frames .................................. 11 - 5.4 Time Fill ....................................... 11 - 5.5 Transmission Considerations ..................... 12 - - 6. Asynchronous to Synchronous Conversion ................ 13 - - 7. Additional LCP Configuration Options .................. 14 - 7.1 Async-Control-Character-Map (ACCM) .............. 14 - - APPENDICES ................................................... 17 - A. Recommended LCP Options ............................... 17 - B. Automatic Recognition of PPP Frames ................... 17 - C. Fast Frame Check Sequence (FCS) Implementation ........ 18 - C.1 FCS table generator ............................. 18 - C.2 16-bit FCS Computation Method ................... 19 - C.3 32-bit FCS Computation Method ................... 21 - - SECURITY CONSIDERATIONS ...................................... 24 - REFERENCES ................................................... 24 - ACKNOWLEDGEMENTS ............................................. 25 - CHAIR'S ADDRESS .............................................. 25 - EDITOR'S ADDRESS ............................................. 25 - - - - -1. Introduction - - This specification provides for framing over both bit-oriented and - octet-oriented synchronous links, and asynchronous links with 8 bits - of data and no parity. These links MUST be full-duplex, but MAY be - either dedicated or circuit-switched. - - An escape mechanism is specified to allow control data such as - XON/XOFF to be transmitted transparently over the link, and to remove - spurious control data which may be injected into the link by - intervening hardware and software. - - Some protocols expect error free transmission, and either provide - error detection only on a conditional basis, or do not provide it at - all. PPP uses the HDLC Frame Check Sequence for error detection. - This is commonly available in hardware implementations, and a - software implementation is provided. - - - - - - -Simpson [Page 1] - RFC 1662 HDLC-like Framing July 1994 - - -1.1. Specification of Requirements - - In this document, several words are used to signify the requirements - of the specification. These words are often capitalized. - - MUST This word, or the adjective "required", means that the - definition is an absolute requirement of the specification. - - MUST NOT This phrase means that the definition is an absolute - prohibition of the specification. - - SHOULD This word, or the adjective "recommended", means that there - may exist valid reasons in particular circumstances to - ignore this item, but the full implications must be - understood and carefully weighed before choosing a - different course. - - MAY This word, or the adjective "optional", means that this - item is one of an allowed set of alternatives. An - implementation which does not include this option MUST be - prepared to interoperate with another implementation which - does include the option. - - -1.2. Terminology - - This document frequently uses the following terms: - - datagram The unit of transmission in the network layer (such as IP). - A datagram may be encapsulated in one or more packets - passed to the data link layer. - - frame The unit of transmission at the data link layer. A frame - may include a header and/or a trailer, along with some - number of units of data. - - packet The basic unit of encapsulation, which is passed across the - interface between the network layer and the data link - layer. A packet is usually mapped to a frame; the - exceptions are when data link layer fragmentation is being - performed, or when multiple packets are incorporated into a - single frame. - - peer The other end of the point-to-point link. - - silently discard - The implementation discards the packet without further - processing. The implementation SHOULD provide the - capability of logging the error, including the contents of - the silently discarded packet, and SHOULD record the event - in a statistics counter. - - -Simpson [Page 2] - RFC 1662 HDLC-like Framing July 1994 - - -2. Physical Layer Requirements - - PPP is capable of operating across most DTE/DCE interfaces (such as, - EIA RS-232-E, EIA RS-422, and CCITT V.35). The only absolute - requirement imposed by PPP is the provision of a full-duplex circuit, - either dedicated or circuit-switched, which can operate in either an - asynchronous (start/stop), bit-synchronous, or octet-synchronous - mode, transparent to PPP Data Link Layer frames. - - Interface Format - - PPP presents an octet interface to the physical layer. There is - no provision for sub-octets to be supplied or accepted. - - Transmission Rate - - PPP does not impose any restrictions regarding transmission rate, - other than that of the particular DTE/DCE interface. - - Control Signals - - PPP does not require the use of control signals, such as Request - To Send (RTS), Clear To Send (CTS), Data Carrier Detect (DCD), and - Data Terminal Ready (DTR). - - When available, using such signals can allow greater functionality - and performance. In particular, such signals SHOULD be used to - signal the Up and Down events in the LCP Option Negotiation - Automaton [1]. When such signals are not available, the - implementation MUST signal the Up event to LCP upon - initialization, and SHOULD NOT signal the Down event. - - Because signalling is not required, the physical layer MAY be - decoupled from the data link layer, hiding the transient details - of the physical transport. This has implications for mobility in - cellular radio networks, and other rapidly switching links. - - When moving from cell to cell within the same zone, an - implementation MAY choose to treat the entire zone as a single - link, even though transmission is switched among several - frequencies. The link is considered to be with the central - control unit for the zone, rather than the individual cell - transceivers. However, the link SHOULD re-establish its - configuration whenever the link is switched to a different - administration. - - Due to the bursty nature of data traffic, some implementations - have choosen to disconnect the physical layer during periods of - - - -Simpson [Page 3] - RFC 1662 HDLC-like Framing July 1994 - - - inactivity, and reconnect when traffic resumes, without informing - the data link layer. Robust implementations should avoid using - this trick over-zealously, since the price for decreased setup - latency is decreased security. Implementations SHOULD signal the - Down event whenever "significant time" has elapsed since the link - was disconnected. The value for "significant time" is a matter of - considerable debate, and is based on the tariffs, call setup - times, and security concerns of the installation. - - - -3. The Data Link Layer - - PPP uses the principles described in ISO 3309-1979 HDLC frame - structure, most recently the fourth edition 3309:1991 [2], which - specifies modifications to allow HDLC use in asynchronous - environments. - - The PPP control procedures use the Control field encodings described - in ISO 4335-1979 HDLC elements of procedures, most recently the - fourth edition 4335:1991 [4]. - - This should not be construed to indicate that every feature of the - above recommendations are included in PPP. Each feature included - is explicitly described in the following sections. - - To remain consistent with standard Internet practice, and avoid - confusion for people used to reading RFCs, all binary numbers in the - following descriptions are in Most Significant Bit to Least - Significant Bit order, reading from left to right, unless otherwise - indicated. Note that this is contrary to standard ISO and CCITT - practice which orders bits as transmitted (network bit order). Keep - this in mind when comparing this document with the international - standards documents. - - - - - - - - - - - - - - - - - -Simpson [Page 4] - RFC 1662 HDLC-like Framing July 1994 - - -3.1. Frame Format - - A summary of the PPP HDLC-like frame structure is shown below. This - figure does not include bits inserted for synchronization (such as - start and stop bits for asynchronous links), nor any bits or octets - inserted for transparency. The fields are transmitted from left to - right. - - +----------+----------+----------+ - | Flag | Address | Control | - | 01111110 | 11111111 | 00000011 | - +----------+----------+----------+ - +----------+-------------+---------+ - | Protocol | Information | Padding | - | 8/16 bits| * | * | - +----------+-------------+---------+ - +----------+----------+----------------- - | FCS | Flag | Inter-frame Fill - |16/32 bits| 01111110 | or next Address - +----------+----------+----------------- - - The Protocol, Information and Padding fields are described in the - Point-to-Point Protocol Encapsulation [1]. - - Flag Sequence - - Each frame begins and ends with a Flag Sequence, which is the - binary sequence 01111110 (hexadecimal 0x7e). All implementations - continuously check for this flag, which is used for frame - synchronization. - - Only one Flag Sequence is required between two frames. Two - consecutive Flag Sequences constitute an empty frame, which is - silently discarded, and not counted as a FCS error. - - Address Field - - The Address field is a single octet, which contains the binary - sequence 11111111 (hexadecimal 0xff), the All-Stations address. - Individual station addresses are not assigned. The All-Stations - address MUST always be recognized and received. - - The use of other address lengths and values may be defined at a - later time, or by prior agreement. Frames with unrecognized - Addresses SHOULD be silently discarded. - - - - - - -Simpson [Page 5] - RFC 1662 HDLC-like Framing July 1994 - - - Control Field - - The Control field is a single octet, which contains the binary - sequence 00000011 (hexadecimal 0x03), the Unnumbered Information - (UI) command with the Poll/Final (P/F) bit set to zero. - - The use of other Control field values may be defined at a later - time, or by prior agreement. Frames with unrecognized Control - field values SHOULD be silently discarded. - - Frame Check Sequence (FCS) Field - - The Frame Check Sequence field defaults to 16 bits (two octets). - The FCS is transmitted least significant octet first, which - contains the coefficient of the highest term. - - A 32-bit (four octet) FCS is also defined. Its use may be - negotiated as described in "PPP LCP Extensions" [5]. - - The use of other FCS lengths may be defined at a later time, or by - prior agreement. - - The FCS field is calculated over all bits of the Address, Control, - Protocol, Information and Padding fields, not including any start - and stop bits (asynchronous) nor any bits (synchronous) or octets - (asynchronous or synchronous) inserted for transparency. This - also does not include the Flag Sequences nor the FCS field itself. - - When octets are received which are flagged in the Async- - Control-Character-Map, they are discarded before calculating - the FCS. - - For more information on the specification of the FCS, see the - Appendices. - - The end of the Information and Padding fields is found by locating - the closing Flag Sequence and removing the Frame Check Sequence - field. - - - - - - - - - - - - - -Simpson [Page 6] - RFC 1662 HDLC-like Framing July 1994 - - -3.2. Modification of the Basic Frame - - The Link Control Protocol can negotiate modifications to the standard - HDLC-like frame structure. However, modified frames will always be - clearly distinguishable from standard frames. - - Address-and-Control-Field-Compression - - When using the standard HDLC-like framing, the Address and Control - fields contain the hexadecimal values 0xff and 0x03 respectively. - When other Address or Control field values are in use, Address- - and-Control-Field-Compression MUST NOT be negotiated. - - On transmission, compressed Address and Control fields are simply - omitted. - - On reception, the Address and Control fields are decompressed by - examining the first two octets. If they contain the values 0xff - and 0x03, they are assumed to be the Address and Control fields. - If not, it is assumed that the fields were compressed and were not - transmitted. - - By definition, the first octet of a two octet Protocol field - will never be 0xff (since it is not even). The Protocol field - value 0x00ff is not allowed (reserved) to avoid ambiguity when - Protocol-Field-Compression is enabled and the first Information - field octet is 0x03. - - - - - - - - - - - - - - - - - - - - - - - - -Simpson [Page 7] - RFC 1662 HDLC-like Framing July 1994 - - -4. Octet-stuffed framing - - This chapter summarizes the use of HDLC-like framing with 8-bit - asynchronous and octet-synchronous links. - - - -4.1. Flag Sequence - - The Flag Sequence indicates the beginning or end of a frame. The - octet stream is examined on an octet-by-octet basis for the value - 01111110 (hexadecimal 0x7e). - - - -4.2. Transparency - - An octet stuffing procedure is used. The Control Escape octet is - defined as binary 01111101 (hexadecimal 0x7d), most significant bit - first. - - As a minimum, sending implementations MUST escape the Flag Sequence - and Control Escape octets. - - After FCS computation, the transmitter examines the entire frame - between the two Flag Sequences. Each Flag Sequence, Control Escape - octet, and any octet which is flagged in the sending Async-Control- - Character-Map (ACCM), is replaced by a two octet sequence consisting - of the Control Escape octet followed by the original octet - exclusive-or'd with hexadecimal 0x20. - - This is bit 5 complemented, where the bit positions are numbered - 76543210 (the 6th bit as used in ISO numbered 87654321 -- BEWARE - when comparing documents). - - Receiving implementations MUST correctly process all Control Escape - sequences. - - On reception, prior to FCS computation, each octet with value less - than hexadecimal 0x20 is checked. If it is flagged in the receiving - ACCM, it is simply removed (it may have been inserted by intervening - data communications equipment). Each Control Escape octet is also - removed, and the following octet is exclusive-or'd with hexadecimal - 0x20, unless it is the Flag Sequence (which aborts a frame). - - A few examples may make this more clear. Escaped data is transmitted - on the link as follows: - - - - -Simpson [Page 8] - RFC 1662 HDLC-like Framing July 1994 - - - - 0x7e is encoded as 0x7d, 0x5e. (Flag Sequence) - 0x7d is encoded as 0x7d, 0x5d. (Control Escape) - 0x03 is encoded as 0x7d, 0x23. (ETX) - - Some modems with software flow control may intercept outgoing DC1 and - DC3 ignoring the 8th (parity) bit. This data would be transmitted on - the link as follows: - - 0x11 is encoded as 0x7d, 0x31. (XON) - 0x13 is encoded as 0x7d, 0x33. (XOFF) - 0x91 is encoded as 0x7d, 0xb1. (XON with parity set) - 0x93 is encoded as 0x7d, 0xb3. (XOFF with parity set) - - - - -4.3. Invalid Frames - - Frames which are too short (less than 4 octets when using the 16-bit - FCS), or which end with a Control Escape octet followed immediately - by a closing Flag Sequence, or in which octet-framing is violated (by - transmitting a "0" stop bit where a "1" bit is expected), are - silently discarded, and not counted as a FCS error. - - - -4.4. Time Fill - -4.4.1. Octet-synchronous - - There is no provision for inter-octet time fill. - - The Flag Sequence MUST be transmitted during inter-frame time fill. - - -4.4.2. Asynchronous - - Inter-octet time fill MUST be accomplished by transmitting continuous - "1" bits (mark-hold state). - - Inter-frame time fill can be viewed as extended inter-octet time - fill. Doing so can save one octet for every frame, decreasing delay - and increasing bandwidth. This is possible since a Flag Sequence may - serve as both a frame end and a frame begin. After having received - any frame, an idle receiver will always be in a frame begin state. - - - - -Simpson [Page 9] - RFC 1662 HDLC-like Framing July 1994 - - - Robust transmitters should avoid using this trick over-zealously, - since the price for decreased delay is decreased reliability. Noisy - links may cause the receiver to receive garbage characters and - interpret them as part of an incoming frame. If the transmitter does - not send a new opening Flag Sequence before sending the next frame, - then that frame will be appended to the noise characters causing an - invalid frame (with high reliability). - - It is suggested that implementations will achieve the best results by - always sending an opening Flag Sequence if the new frame is not - back-to-back with the last. Transmitters SHOULD send an open Flag - Sequence whenever "appreciable time" has elapsed after the prior - closing Flag Sequence. The maximum value for "appreciable time" is - likely to be no greater than the typing rate of a slow typist, about - 1 second. - - - -4.5. Transmission Considerations - -4.5.1. Octet-synchronous - - The definition of various encodings and scrambling is the - responsibility of the DTE/DCE equipment in use, and is outside the - scope of this specification. - - -4.5.2. Asynchronous - - All octets are transmitted least significant bit first, with one - start bit, eight bits of data, and one stop bit. There is no - provision for seven bit asynchronous links. - - - - - - - - - - - - - - - - - - -Simpson [Page 10] - RFC 1662 HDLC-like Framing July 1994 - - -5. Bit-stuffed framing - - This chapter summarizes the use of HDLC-like framing with bit- - synchronous links. - - - -5.1. Flag Sequence - - The Flag Sequence indicates the beginning or end of a frame, and is - used for frame synchronization. The bit stream is examined on a - bit-by-bit basis for the binary sequence 01111110 (hexadecimal 0x7e). - - The "shared zero mode" Flag Sequence "011111101111110" SHOULD NOT be - used. When not avoidable, such an implementation MUST ensure that - the first Flag Sequence detected (the end of the frame) is promptly - communicated to the link layer. Use of the shared zero mode hinders - interoperability with bit-synchronous to asynchronous and bit- - synchronous to octet-synchronous converters. - - - -5.2. Transparency - - After FCS computation, the transmitter examines the entire frame - between the two Flag Sequences. A "0" bit is inserted after all - sequences of five contiguous "1" bits (including the last 5 bits of - the FCS) to ensure that a Flag Sequence is not simulated. - - On reception, prior to FCS computation, any "0" bit that directly - follows five contiguous "1" bits is discarded. - - - -5.3. Invalid Frames - - Frames which are too short (less than 4 octets when using the 16-bit - FCS), or which end with a sequence of more than six "1" bits, are - silently discarded, and not counted as a FCS error. - - - -5.4. Time Fill - - There is no provision for inter-octet time fill. - - The Flag Sequence SHOULD be transmitted during inter-frame time fill. - However, certain types of circuit-switched links require the use of - - - -Simpson [Page 11] - RFC 1662 HDLC-like Framing July 1994 - - - mark idle (continuous ones), particularly those that calculate - accounting based on periods of bit activity. When mark idle is used - on a bit-synchronous link, the implementation MUST ensure at least 15 - consecutive "1" bits between Flags during the idle period, and that - the Flag Sequence is always generated at the beginning of a frame - after an idle period. - - This differs from practice in ISO 3309, which allows 7 to 14 bit - mark idle. - - - -5.5. Transmission Considerations - - All octets are transmitted least significant bit first. - - The definition of various encodings and scrambling is the - responsibility of the DTE/DCE equipment in use, and is outside the - scope of this specification. - - While PPP will operate without regard to the underlying - representation of the bit stream, lack of standards for transmission - will hinder interoperability as surely as lack of data link - standards. At speeds of 56 Kbps through 2.0 Mbps, NRZ is currently - most widely available, and on that basis is recommended as a default. - - When configuration of the encoding is allowed, NRZI is recommended as - an alternative, because of its relative immunity to signal inversion - configuration errors, and instances when it MAY allow connection - without an expensive DSU/CSU. Unfortunately, NRZI encoding - exacerbates the missing x1 factor of the 16-bit FCS, so that one - error in 2**15 goes undetected (instead of one in 2**16), and triple - errors are not detected. Therefore, when NRZI is in use, it is - recommended that the 32-bit FCS be negotiated, which includes the x1 - factor. - - At higher speeds of up to 45 Mbps, some implementors have chosen the - ANSI High Speed Synchronous Interface [HSSI]. While this experience - is currently limited, implementors are encouraged to cooperate in - choosing transmission encoding. - - - - - - - - - - - -Simpson [Page 12] - RFC 1662 HDLC-like Framing July 1994 - - -6. Asynchronous to Synchronous Conversion - - There may be some use of asynchronous-to-synchronous converters (some - built into modems and cellular interfaces), resulting in an - asynchronous PPP implementation on one end of a link and a - synchronous implementation on the other. It is the responsibility of - the converter to do all stuffing conversions during operation. - - To enable this functionality, synchronous PPP implementations MUST - always respond to the Async-Control-Character-Map Configuration - Option with the LCP Configure-Ack. However, acceptance of the - Configuration Option does not imply that the synchronous - implementation will do any ACCM mapping. Instead, all such octet - mapping will be performed by the asynchronous-to-synchronous - converter. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Simpson [Page 13] - RFC 1662 HDLC-like Framing July 1994 - - -7. Additional LCP Configuration Options - - The Configuration Option format and basic options are already defined - for LCP [1]. - - Up-to-date values of the LCP Option Type field are specified in the - most recent "Assigned Numbers" RFC [10]. This document concerns the - following values: - - 2 Async-Control-Character-Map - - - - -7.1. Async-Control-Character-Map (ACCM) - - Description - - This Configuration Option provides a method to negotiate the use - of control character transparency on asynchronous links. - - Each end of the asynchronous link maintains two Async-Control- - Character-Maps. The receiving ACCM is 32 bits, but the sending - ACCM may be up to 256 bits. This results in four distinct ACCMs, - two in each direction of the link. - - For asynchronous links, the default receiving ACCM is 0xffffffff. - The default sending ACCM is 0xffffffff, plus the Control Escape - and Flag Sequence characters themselves, plus whatever other - outgoing characters are flagged (by prior configuration) as likely - to be intercepted. - - For other types of links, the default value is 0, since there is - no need for mapping. - - The default inclusion of all octets less than hexadecimal 0x20 - allows all ASCII control characters [6] excluding DEL (Delete) - to be transparently communicated through all known data - communications equipment. - - The transmitter MAY also send octets with values in the range 0x40 - through 0xff (except 0x5e) in Control Escape format. Since these - octet values are not negotiable, this does not solve the problem - of receivers which cannot handle all non-control characters. - Also, since the technique does not affect the 8th bit, this does - not solve problems for communications links that can send only 7- - bit characters. - - - - -Simpson [Page 14] - RFC 1662 HDLC-like Framing July 1994 - - - Note that this specification differs in detail from later - amendments, such as 3309:1991/Amendment 2 [3]. However, such - "extended transparency" is applied only by "prior agreement". - Use of the transparency methods in this specification - constitute a prior agreement with respect to PPP. - - For compatibility with 3309:1991/Amendment 2, the transmitter - MAY escape DEL and ACCM equivalents with the 8th (most - significant) bit set. No change is required in the receiving - algorithm. - - Following ACCM negotiation, the transmitter SHOULD cease - escaping DEL. - - However, it is rarely necessary to map all control characters, and - often it is unnecessary to map any control characters. The - Configuration Option is used to inform the peer which control - characters MUST remain mapped when the peer sends them. - - The peer MAY still send any other octets in mapped format, if it - is necessary because of constraints known to the peer. The peer - SHOULD Configure-Nak with the logical union of the sets of mapped - octets, so that when such octets are spuriously introduced they - can be ignored on receipt. - - A summary of the Async-Control-Character-Map Configuration Option - format is shown below. The fields are transmitted from left to - right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | ACCM - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ACCM (cont) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - Type - - 2 - - Length - - 6 - - - - - - -Simpson [Page 15] - RFC 1662 HDLC-like Framing July 1994 - - - ACCM - - The ACCM field is four octets, and indicates the set of control - characters to be mapped. The map is sent most significant octet - first. - - Each numbered bit corresponds to the octet of the same value. If - the bit is cleared to zero, then that octet need not be mapped. - If the bit is set to one, then that octet MUST remain mapped. For - example, if bit 19 is set to zero, then the ASCII control - character 19 (DC3, Control-S) MAY be sent in the clear. - - Note: The least significant bit of the least significant octet - (the final octet transmitted) is numbered bit 0, and would map - to the ASCII control character NUL. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Simpson [Page 16] - RFC 1662 HDLC-like Framing July 1994 - - -A. Recommended LCP Options - - The following Configurations Options are recommended: - - High Speed links - - Magic Number - Link Quality Monitoring - No Address and Control Field Compression - No Protocol Field Compression - - - Low Speed or Asynchronous links - - Async Control Character Map - Magic Number - Address and Control Field Compression - Protocol Field Compression - - - -B. Automatic Recognition of PPP Frames - - It is sometimes desirable to detect PPP frames, for example during a - login sequence. The following octet sequences all begin valid PPP - LCP frames: - - 7e ff 03 c0 21 - 7e ff 7d 23 c0 21 - 7e 7d df 7d 23 c0 21 - - Note that the first two forms are not a valid username for Unix. - However, only the third form generates a correctly checksummed PPP - frame, whenever 03 and ff are taken as the control characters ETX and - DEL without regard to parity (they are correct for an even parity - link) and discarded. - - Many implementations deal with this by putting the interface into - packet mode when one of the above username patterns are detected - during login, without examining the initial PPP checksum. The - initial incoming PPP frame is discarded, but a Configure-Request is - sent immediately. - - - - - - - - - -Simpson [Page 17] - RFC 1662 HDLC-like Framing July 1994 - - -C. Fast Frame Check Sequence (FCS) Implementation - - The FCS was originally designed with hardware implementations in - mind. A serial bit stream is transmitted on the wire, the FCS is - calculated over the serial data as it goes out, and the complement of - the resulting FCS is appended to the serial stream, followed by the - Flag Sequence. - - The receiver has no way of determining that it has finished - calculating the received FCS until it detects the Flag Sequence. - Therefore, the FCS was designed so that a particular pattern results - when the FCS operation passes over the complemented FCS. A good - frame is indicated by this "good FCS" value. - - - -C.1. FCS table generator - - The following code creates the lookup table used to calculate the - FCS-16. - - /* - * Generate a FCS-16 table. - * - * Drew D. Perkins at Carnegie Mellon University. - * - * Code liberally borrowed from Mohsen Banan and D. Hugh Redelmeier. - */ - - /* - * The FCS-16 generator polynomial: x**0 + x**5 + x**12 + x**16. - */ - #define P 0x8408 - - - main() - { - register unsigned int b, v; - register int i; - - printf("typedef unsigned short u16;\n"); - printf("static u16 fcstab[256] = {"); - for (b = 0; ; ) { - if (b % 8 == 0) - printf("\n"); - - v = b; - for (i = 8; i--; ) - - - -Simpson [Page 18] - RFC 1662 HDLC-like Framing July 1994 - - - v = v & 1 ? (v >> 1) ^ P : v >> 1; - - printf("\t0x%04x", v & 0xFFFF); - if (++b == 256) - break; - printf(","); - } - printf("\n};\n"); - } - - - -C.2. 16-bit FCS Computation Method - - The following code provides a table lookup computation for - calculating the Frame Check Sequence as data arrives at the - interface. This implementation is based on [7], [8], and [9]. - - /* - * u16 represents an unsigned 16-bit number. Adjust the typedef for - * your hardware. - */ - typedef unsigned short u16; - - /* - * FCS lookup table as calculated by the table generator. - */ - static u16 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, - - - -Simpson [Page 19] - RFC 1662 HDLC-like Framing July 1994 - - - 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 PPPINITFCS16 0xffff /* Initial FCS value */ - #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */ - - /* - * Calculate a new fcs given the current fcs and the new data. - */ - u16 pppfcs16(fcs, cp, len) - register u16 fcs; - register unsigned char *cp; - register int len; - { - ASSERT(sizeof (u16) == 2); - ASSERT(((u16) -1) > 0); - while (len--) - fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; - - return (fcs); - } - - /* - * How to use the fcs - */ - tryfcs16(cp, len) - register unsigned char *cp; - register int len; - { - u16 trialfcs; - - /* add on output */ - trialfcs = pppfcs16( PPPINITFCS16, cp, len ); - trialfcs ^= 0xffff; /* complement */ - cp[len] = (trialfcs & 0x00ff); /* least significant byte first */ - cp[len+1] = ((trialfcs >> 8) & 0x00ff); - - - - -Simpson [Page 20] - RFC 1662 HDLC-like Framing July 1994 - - - /* check on input */ - trialfcs = pppfcs16( PPPINITFCS16, cp, len + 2 ); - if ( trialfcs == PPPGOODFCS16 ) - printf("Good FCS\n"); - } - - - -C.3. 32-bit FCS Computation Method - - The following code provides a table lookup computation for - calculating the 32-bit Frame Check Sequence as data arrives at the - interface. - - /* - * The FCS-32 generator polynomial: x**0 + x**1 + x**2 + x**4 + x**5 - * + x**7 + x**8 + x**10 + x**11 + x**12 + x**16 - * + x**22 + x**23 + x**26 + x**32. - */ - - /* - * u32 represents an unsigned 32-bit number. Adjust the typedef for - * your hardware. - */ - typedef unsigned long u32; - - static u32 fcstab_32[256] = - { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - - - -Simpson [Page 21] - RFC 1662 HDLC-like Framing July 1994 - - - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - - #define PPPINITFCS32 0xffffffff /* Initial FCS value */ - #define PPPGOODFCS32 0xdebb20e3 /* Good final FCS value */ - - - -Simpson [Page 22] - RFC 1662 HDLC-like Framing July 1994 - - - /* - * Calculate a new FCS given the current FCS and the new data. - */ - u32 pppfcs32(fcs, cp, len) - register u32 fcs; - register unsigned char *cp; - register int len; - { - ASSERT(sizeof (u32) == 4); - ASSERT(((u32) -1) > 0); - while (len--) - fcs = (((fcs) >> 8) ^ fcstab_32[((fcs) ^ (*cp++)) & 0xff]); - - return (fcs); - } - - /* - * How to use the fcs - */ - tryfcs32(cp, len) - register unsigned char *cp; - register int len; - { - u32 trialfcs; - - /* add on output */ - trialfcs = pppfcs32( PPPINITFCS32, cp, len ); - trialfcs ^= 0xffffffff; /* complement */ - cp[len] = (trialfcs & 0x00ff); /* least significant byte first */ - cp[len+1] = ((trialfcs >>= 8) & 0x00ff); - cp[len+2] = ((trialfcs >>= 8) & 0x00ff); - cp[len+3] = ((trialfcs >> 8) & 0x00ff); - - /* check on input */ - trialfcs = pppfcs32( PPPINITFCS32, cp, len + 4 ); - if ( trialfcs == PPPGOODFCS32 ) - printf("Good FCS\n"); - } - - - - - - - - - - - - - -Simpson [Page 23] - RFC 1662 HDLC-like Framing July 1994 - - -Security Considerations - - As noted in the Physical Layer Requirements section, the link layer - might not be informed when the connected state of the physical layer - has changed. This results in possible security lapses due to over- - reliance on the integrity and security of switching systems and - administrations. An insertion attack might be undetected. An - attacker which is able to spoof the same calling identity might be - able to avoid link authentication. - - - -References - - [1] Simpson, W., Editor, "The Point-to-Point Protocol (PPP)", - STD 50, RFC 1661, Daydreamer, July 1994. - - [2] ISO/IEC 3309:1991(E), "Information Technology - - Telecommunications and information exchange between systems - - High-level data link control (HDLC) procedures - Frame - structure", International Organization For Standardization, - Fourth edition 1991-06-01. - - [3] ISO/IEC 3309:1991/Amd.2:1992(E), "Information Technology - - Telecommunications and information exchange between systems - - High-level data link control (HDLC) procedures - Frame - structure - Amendment 2: Extended transparency options for - start/stop transmission", International Organization For - Standardization, 1992-01-15. - - [4] ISO/IEC 4335:1991(E), "Information Technology - - Telecommunications and information exchange between systems - - High-level data link control (HDLC) procedures - Elements of - procedures", International Organization For Standardization, - Fourth edition 1991-09-15. - - [5] Simpson, W., Editor, "PPP LCP Extensions", RFC 1570, - Daydreamer, January 1994. - - [6] ANSI X3.4-1977, "American National Standard Code for - Information Interchange", American National Standards - Institute, 1977. - - [7] Perez, "Byte-wise CRC Calculations", IEEE Micro, June 1983. - - [8] Morse, G., "Calculating CRC's by Bits and Bytes", Byte, - September 1986. - - - - -Simpson [Page 24] - RFC 1662 HDLC-like Framing July 1994 - - - [9] LeVan, J., "A Fast CRC", Byte, November 1987. - - [10] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC - 1340, USC/Information Sciences Institute, July 1992. - - - -Acknowledgements - - This document is the product of the Point-to-Point Protocol Working - Group of the Internet Engineering Task Force (IETF). Comments should - be submitted to the ietf-ppp@merit.edu mailing list. - - This specification is based on previous RFCs, where many - contributions have been acknowleged. - - The 32-bit FCS example code was provided by Karl Fox (Morning Star - Technologies). - - Special thanks to Morning Star Technologies for providing computing - resources and network access support for writing this specification. - - - -Chair's Address - - The working group can be contacted via the current chair: - - Fred Baker - Advanced Computer Communications - 315 Bollay Drive - Santa Barbara, California 93117 - - fbaker@acc.com - - -Editor's Address - - Questions about this memo can also be directed to: - - William Allen Simpson - Daydreamer - Computer Systems Consulting Services - 1384 Fontaine - Madison Heights, Michigan 48071 - - Bill.Simpson@um.cc.umich.edu - bsimpson@MorningStar.com - - -Simpson [Page 25] - - - - - diff --git a/ext/picotcp/RFC/rfc1877.txt b/ext/picotcp/RFC/rfc1877.txt deleted file mode 100644 index 843c15c..0000000 --- a/ext/picotcp/RFC/rfc1877.txt +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - -Network Working Group S. Cobb -Request for Comments: 1877 Microsoft -Category: Informational December 1995 - - - PPP Internet Protocol Control Protocol Extensions for - Name Server Addresses - -Status of this Memo - - This memo provides information for the Internet community. This memo - does not specify an Internet standard of any kind. Distribution of - this memo is unlimited. - -Abstract - - The Point-to-Point Protocol (PPP) [1] provides a standard method for - transporting multi-protocol datagrams over point-to-point links. PPP - defines an extensible Link Control Protocol and a family of Network - Control Protocols (NCPs) for establishing and configuring different - network-layer protocols. - - This document extends the NCP for establishing and configuring the - Internet Protocol over PPP [2], defining the negotiation of primary - and secondary Domain Name System (DNS) [3] and NetBIOS Name Server - (NBNS) [4] addresses. - -Table of Contents - - 1. Additional IPCP Configuration options ................. 1 - 1.1 Primary DNS Server Address .................... 2 - 1.2 Primary NBNS Server Address ................... 3 - 1.3 Secondary DNS Server Address .................. 4 - 1.4 Secondary NBNS Server Address ................. 5 - REFRENCES .................................................... 6 - SECURITY CONSIDERATIONS ...................................... 6 - CHAIR'S ADDRESS .............................................. 6 - AUTHOR'S ADDRESS ............................................. 6 - -1. Additional IPCP Configuration Options - - The four name server address configuration options, 129 to 132, - provide a method of obtaining the addresses of Domain Name System - (DNS) servers and (NetBIOS Name Server (NBNS) nodes on the remote - network. - - - - - - -Cobb Informational [Page 1] - -RFC 1877 PPP IPCP Extensions December 1995 - - - Primary and secondary addresses are negotiated independently. They - serve identical purposes, except that when both are present an - attempt SHOULD be made to resolve names using the primary address - before using the secondary address. - - For implementational convenience, these options are designed to be - identical in format and behavior to option 3 (IP-Address) which is - already present in most IPCP implementations. - - Since the usefulness of name server address information is dependent - on the topology of the remote network and local peer's application, - it is suggested that these options not be included in the list of - "IPCP Recommended Options". - -1.1. Primary DNS Server Address - - Description - - This Configuration Option defines a method for negotiating with - the remote peer the address of the primary DNS server to be used - on the local end of the link. If local peer requests an invalid - server address (which it will typically do intentionally) the - remote peer specifies the address by NAKing this option, and - returning the IP address of a valid DNS server. - - By default, no primary DNS address is provided. - - A summary of the Primary DNS Address Configuration Option format is - shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Primary-DNS-Address - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - Primary-DNS-Address (cont) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 129 - - Length - - 6 - - - - - - -Cobb Informational [Page 2] - -RFC 1877 PPP IPCP Extensions December 1995 - - - Primary-DNS-Address - - The four octet Primary-DNS-Address is the address of the primary - DNS server to be used by the local peer. If all four octets are - set to zero, it indicates an explicit request that the peer - provide the address information in a Config-Nak packet. - - Default - - No address is provided. - -1.2. Primary NBNS Server Address - - Description - - This Configuration Option defines a method for negotiating with - the remote peer the address of the primary NBNS server to be used - on the local end of the link. If local peer requests an invalid - server address (which it will typically do intentionally) the - remote peer specifies the address by NAKing this option, and - returning the IP address of a valid NBNS server. - - By default, no primary NBNS address is provided. - - A summary of the Primary NBNS Address Configuration Option format is - shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Primary-NBNS-Address - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - Primary-NBNS-Address (cont) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 130 - - Length - - 6 - - Primary-NBNS-Address - - The four octet Primary-NBNS-Address is the address of the primary - NBNS server to be used by the local peer. If all four octets are - set to zero, it indicates an explicit request that the peer - - - -Cobb Informational [Page 3] - -RFC 1877 PPP IPCP Extensions December 1995 - - - provide the address information in a Config-Nak packet. - - Default - - No address is provided. - -1.3. Secondary DNS Server Address - - Description - - This Configuration Option defines a method for negotiating with - the remote peer the address of the secondary DNS server to be used - on the local end of the link. If local peer requests an invalid - server address (which it will typically do intentionally) the - remote peer specifies the address by NAKing this option, and - returning the IP address of a valid DNS server. - - By default, no secondary DNS address is provided. - - A summary of the Secondary DNS Address Configuration Option format is - shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Secondary-DNS-Address - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - Secondary-DNS-Address (cont) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 131 - - Length - - 6 - - Secondary-DNS-Address - - The four octet Secondary-DNS-Address is the address of the primary - NBNS server to be used by the local peer. If all four octets are - set to zero, it indicates an explicit request that the peer - provide the address information in a Config-Nak packet. - - Default - - No address is provided. - - - -Cobb Informational [Page 4] - -RFC 1877 PPP IPCP Extensions December 1995 - - -1.4. Secondary NBNS Server Address - - Description - - This Configuration Option defines a method for negotiating with - the remote peer the address of the secondary NBNS server to be - used on the local end of the link. If local peer requests an - invalid server address (which it will typically do intentionally) - the remote peer specifies the address by NAKing this option, and - returning the IP address of a valid NBNS server. - - By default, no secondary NBNS address is provided. - - A summary of the Secondary NBNS Address Configuration Option format - is shown below. The fields are transmitted from left to right. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Secondary-NBNS-Address - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - Secondary-NBNS-Address (cont) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Type - - 132 - - Length - - 6 - - Secondary-NBNS-Address - - The four octet Secondary-NBNS-Address is the address of the - secondary NBNS server to be used by the local peer. If all - four octets are set to zero, it indicates an explicit request - that the peer provide the address information in a Config-Nak - packet. - - Default - - No address is provided. - - - - - - - - -Cobb Informational [Page 5] - -RFC 1877 PPP IPCP Extensions December 1995 - - -References - - [1] Simpson, W., Editor, "The Point-to-Point Protocol (PPP)", STD 51, - RFC 1661, Daydreamer, July 1994. - - [2] McGregor, G., "PPP Internet Control Protocol", RFC 1332, Merit, - May 1992. - - [3] Auerbach, K., and A. Aggarwal, "Protocol Standard for a NetBIOS - Service on a TCP/UDP Transport", STD 19, RFCs 1001 and 1002, - March 1987. - - [4] Mockapetris, P., "Domain Names - Concepts and Facilities", STD - 13, RFC 1034, USC/Information Sciences Institute, November 1987. - - [5] Mockapetris, P., "Domain Names - Implementation and - Specification", STD 13, RFC 1035, USC/Information Sciences - Institute, November 1987. - -Security Considerations - - Security issues are not discussed in this memo. - -Chair's Address - - The working group can be contacted via the current chair: - - Fred Baker - Cisco Systems - 519 Lado Drive - Santa Barbara, California 93111 - - EMail: fred@cisco.com - -Author's Address - - Questions about this memo can also be directed to: - - Steve Cobb - Microsoft Corporation - One Microsoft Way - Redmond, WA 98052-6399 - - Phone: (206) 882-8080 - - EMail: stevec@microsoft.com - - - - - -Cobb Informational [Page 6] - diff --git a/ext/picotcp/RFC/rfc1936.txt b/ext/picotcp/RFC/rfc1936.txt deleted file mode 100644 index 479fe37..0000000 --- a/ext/picotcp/RFC/rfc1936.txt +++ /dev/null @@ -1,1179 +0,0 @@ - - - - - - -Network Working Group J. Touch -Request For Comments: 1936 B. Parham -Category: Informational ISI - April 1996 - - - Implementing the Internet Checksum in Hardware - -Status of This Memo - - This memo provides information for the Internet community. This memo - does not specify an Internet standard of any kind. Distribution of - this memo is unlimited. - -Abstract - - This memo presents a techniques for efficiently implementing the - Internet Checksum in hardware. It includes PLD code for programming a - single, low cost part to perform checksumming at 1.26 Gbps. - -Introduction - - The Internet Checksum is used in various Internet protocols to check - for data corruption in headers (e.g., IP) [4] and packet bodies (e.g, - UDP, TCP) [5][6]. Efficient software implementation of this checksum - has been addressed in previous RFCs [1][2][3][7]. - - Efficient software implementations of the Internet Checksum algorithm - are often embedded in data copying operations ([1], Section 2). This - copy operation is increasingly being performed by dedicated direct - memory access (DMA) hardware. As a result, DMA hardware designs are - beginning to incorporate dedicated hardware to compute the Internet - Checksum during the data transfer. - - This note presents the architecture of an efficient, pipelined - Internet Checksum mechanism, suitable for inclusion in DMA hardware - [8]. This design can be implemented in a relatively inexpensive - programmable logic device (PLD) (1995 cost of $40), and is capable of - supporting 1.26 Gbps transfer rates, at 26 ns per 32-bit word. - Appendix A provides the pseudocode for such a device. This design has - been implemented in the PC-ATOMIC host interface hardware [8]. We - believe this design is of general use to the Internet community. - - - - - - - - - -Touch & Parham Informational [Page 1] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - - The remainder of this document is organized as follows: - - Review of the Internet Checksum - One's Complement vs. Two's Complement Addition - Interfaces - Summary - Appendix A - PLD source code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Touch & Parham Informational [Page 2] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -A Review of the Internet Checksum - - The Internet Checksum is used for detecting corruption in a block of - data [1]. It is initialized to zero, and computed as the complement - of the ones-complement sum of the data, taken in 16-bit units. A - subsequent checksum of the data and checksum together should generate - a zero checksum if no errors are detected. - - The checksum allows [1]: - - - byte order "independence" - reordered output is equivalent to reordered input - - 16-bit word-order independence - reordering 16-bit words preserves the output - - incremental computation - - deferred carries - - parallel summation - a result of deferred carries, incremental - computation, and 16-bit word order independence - - This note describes an implementation that computes two partial - checksums in parallel, over the odd and even 16-bit half-words of - 32-bit data. The result is a pair of partial checksums (odd and - even), which can be combined, and the result inverted to generate the - true Internet Checksum. This technique is related to the long-word - parallel summation used in efficient software implementations [1]. - - +------------------+ +------------------+ - | high half-word | | low half-word | - | ones-complement | | ones-complement | - | partial checksum | | partial checksum | - +------------------+ +------------------+ - \ / - * (ones-complement sum) - | - +------------------+ - | partial checksum | - +------------------+ - | - * (ones-complement negative) - | - +-------------------+ - | final | - | Internet Checksum | - +-------------------+ - - - - - - -Touch & Parham Informational [Page 3] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -One's Complement vs. Two's Complement Addition - - The Internet Checksum is composed of a ones-complement lookahead - adder and a bit-wise inverter. A ones-complement adder can be built - either using twos-complement components, or natively. - - A twos-complement implementation of a ones-complement adder requires - either two twos-complement adders, or two cycles per add. The sum is - performed, then the high-bit carry-out is propagated to the carry-in, - and a second sum is performed. (ones-complement addition is {+1s} and - twos-complement is {+2s}) - - a {+1s} b == (a {+2s} b) + carry(a {+2s} b) - - e.g., - halfword16 a,b; - word32 c; - a {+1s} b == r - such that: - c = a {+2s} b; # sum value - r = (c & 0xFFFF) {+2s} (c >> 16); # sum carry - - Bits of a twos-complement lookahead adder are progressively more - complex in carry lookahead. (OR the contents of each row, where terms - are AND'd or XOR'd {^}) - - 4-bit carry-lookahead 2's complement adder: - a,b : input data - p : carry propagate, where pi = ai*bi = (ai)(bi) - g : carry generate, where gi = ai + bi - - Out0 := a0 ^ b0 ^ ci - - Out1 := a1 ^ b1 ^ (cip0 + g0) - - Out2 := a2 ^ b2 ^ (cip0p1 + g0p1 + g1) - - Out3 := a3 ^ b3 ^ (cip0p1p2 + g0p1p2 + g1p2 + g2) - - Cout := cip0p1p2p3 + g0p1p2p3 + g1p2p3 + g2p3 + g3 - - The true ones-complement lookahead adder recognizes that the carry- - wrap of the twos-complement addition is equivalent to a toroidal - carry-lookahead. Bits of a ones-complement lookahead adder are all - the same complexity, that of the high-bit of a twos-complement - lookahead adder. Thus the ones-complement sum (and thus the Internet - Checksum) is bit-position independent. We replace `ci' with the `co' - expression and reduce. (OR terms in each row pair). - - - -Touch & Parham Informational [Page 4] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - - 4-bit carry-lookahead 1's complement ring adder: - - Out0 = a0 ^ b0 ^ (g3 + g2p3 + g1p2p3 + g0p1p2p3) - - Out1 = a1 ^ b1 ^ (g3p0 + g2p3p0 + g1p2p3p0 + g0) - - Out2 = a2 ^ b2 ^ (g3p0p1 + g2p3p0p1 + g1 + g0p1) - - Out3 = a3 ^ b3 ^ (g3p0p1p2 + g2 + g1p2 + g0p1p2) - - A hardware implementation can use this toroidal design directly, - together with conventional twos-complement fast-adder internal - components, to perform a pipelined ones-complement adder [8]. - - A VLSI implementation could use any full-lookahead adder, adapted to - be toroidal and bit-equivalent, as above. In our PLD implementation, - we implement the adders via 2- and 3-bit full-lookahead sub- - components. The adder components are chained in a ring via carry bit - registers. This relies on delayed carry-propagation to implement a - carry pipeline between the fast-adder stages. - - Full-lookahead adders in a toroidal pipeline - - +-+-+-+ +-+-+-+ +-+-+ +-+-+-+ +-+-+-+ +-+-+ - |i|i|i| |i|i|i| |i|i| |i|i|i| |i|i|i| |i|i| - |F|E|D| |C|B|A| |9|8| |7|6|5| |4|3|2| |1|0| - +-+-+-+ +-+-+-+ +-+-+ +-+-+-+ +-+-+-+ +-+-+ - "+" "+" "+" "+" "+" "+" - +-+-+-+ +-+-+-+ +-+-+ +-+-+-+ +-+-+-+ +-+-+ - |s|s|s| |s|s|s| |s|s| |s|s|s| |s|s|s| |s|s| - |F|E|D| |C|B|A| |9|8| |7|6|5| |4|3|2| |1|0| - +-+-+-+ +-+-+-+ +-+-+ +-+-+-+ +-+-+-+ +-+-+ - v | v | v | v | v | v | +--+ - | ^ | ^ | ^ | ^ | ^ | ^ v | - | +-+ +-+ +-+ +-+ +-+ +-+ | - | |c| |c| |c| |c| |c| |c| | - | |5| |4| |3| |2| |1| |0| | - | +-+ +-+ +-+ +-+ +-+ +-+ | - +----------------------------------------------------------+ - - Implementation of fast-adders in PLD hardware is currently limited to - 3-bits, because an i-bit adder requires 4+2^i product terms, and - current PLDs support only 16 product terms. The resulting device - takes at most 5 "idle" clock periods for the carries to propagate - through the accumulation pipeline. - - - - - - -Touch & Parham Informational [Page 5] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -Interfaces - - The above device has been installed in a VL-Bus PC host interface - card [8]. It has a hardware and software interface, defined as - follows. - - Hardware Interface - - The Internet Checksum hardware appears as a single-port 32-bit - register, with clock and control signals [8]: - - +----------------------+ - CLR--->| | - OE---->| 32-bit register as | - CLK--->| 2 adjacent 16-bit |<---/---> 32-bit data bus - ICLK-->| ones-complement sums | - ADD--->| | - +----------------------+ - - CLR = zero the register - OE = write the register onto the data bus - CLK = clock to cycle the pipeline operation - ICLK = input data latch clock - ADD = initiating an add of latched input data - - CLR causes the contents of the checksum register and input latch to - be zeroed. There is no explicit load; a CLR followed by a write of - the load value to a dummy location is equivalent. - - The OE causes the register to be written to the data bus, or tri- - stated. - - The CLK causes the pipeline to operate. If no new input data is - latched to be added (via ICLK, ADD), a virtual "zero" is summed into - the register, to permit the pipeline to empty. - - The ICLK (transparently) latches the value on the data bus to be - latched internally, to be summed into the accumulator on the next ADD - signal. The ADD signal causes the latched input data (ICLK) to be - accumulated into the checksum pipeline. ADD and ICLK are commonly - tied together. One 32-bit data value can be latched and accumulated - into the pipeline adder every 26-ns clock, assuming data is stable - when the ADD/ICLK signal occurs. - - The internal 32-bit register is organized as two 16-bit ones- - complement sums, over the even and odd 16-bit words of the data - stream. To compute the Internet Checksum from this quantity, ones- - complement add the halves together, and invert the result. - - - -Touch & Parham Informational [Page 6] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - - Software Interface - - The device is used as a memory-mapped register. The register is read - by performing a read on its equivalent memory location. - - The device is controlled via an external memory-mapped register. Bits - in this control register clear the device (set/clear the CLR line), - and enable and disable the device (set/clear the ADD line). The CLR - line can alternatively be mapped to a memory write, e.g., such that - reading the location is a non-destructive read of the checksum - register, and a write of any value clears the checksum register. The - enable/disable control must be stored in an external register. - - The device is designed to operate in background during memory - transfers (either DMA or programmed I/O). Once enabled, all transfers - across that bus are summed into the checksum register. The checksum - is available 5 clocks after the last enabled data accumulation. This - delay is often hidden by memory access mechanisms and bus - arbitration. If required, "stall" instructions can be executed for - the appropriate delay. - - For the following example, we assume that the device is located at - CKSUMLOC. We assume that reading that location reads the checksum - register, and writing any value to that location clears the register. - The control register is located at CTLLOC, and the checksum - enable/disable bit is CKSUMBIT, where 1 is enabled, and 0 is - disabled. To perform a checksum, a programmer would clear the - register, (optionally initialize the checksum), initiate a series of - transfers, and use the result: - - /******* initialization *******/ - *(CTLLOC) &= ~((ctlsize)(CKSUMBIT)); /* disable sum */ - (word32)(*(CKSUMLOC)) = 0; /* clear reg */ - *(CTLLOC) |= CKSUMBIT; /* enable sum */ - { (optional) write initial value to a dummy location } - - /***** perform a transfer *****/ - { do one or more DMA or PIO transfers - read or write } - - /***** gather the results *****/ - *(CTLLOC) &= ~((ctlsize)(CKSUMBIT)); /* disable sum */ - sum = (word32)(*(CKSUMLOC)); /* read sum */ - sum = (sum & 0xFFFF) + (sum >> 16); /* fold halves */ - sum = (sum & 0xFFFF) + (sum >> 16); /* add in carry */ - ipcksum = (halfword16)(~(sum & 0xFFFF)); /* 1's negative */ - - - - - - -Touch & Parham Informational [Page 7] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -Summary - - This note describes the design of a hardware Internet Checksum that - can be implemented in an inexpensive PLD, achieving 1.26 Gbps. This - design has been implemented in the PC-ATOMIC host interface hardware - [8]. We believe this design is of general use to the Internet - community. - -Security Considerations - - Security considerations are not addressed here. The Internet Checksum - is not intended as a security measure. - -Acknowledgements - - The authors would like to thank the members of the "High-Performance - Computing and Communications", notably Mike Carlton, and "Advanced - Systems" Divisions at ISI for their assistance in the development of - the hardware, and this memo. - -References - - [1] Braden, R., Borman, D., and Partridge, C., "Computing the - Internet Checksum," Network Working Group RFC-1071, ISI, Cray - Research, and BBN Labs, Sept. 1988. - - [2] Mallory, T., and Kullberg, A., "Incremental Updating of the - Internet Checksum," Network Working Group RFC-1141, BBN Comm., - Jan. 1990. - - [3] Plummer, W., "TCP Checksum Function Design," IEN-45, BBN, 1978, - included as an appendix in RFC-1071. - - [4] Postel, Jon, "Internet Protocol," Network Working Group RFC- - 791/STD-5, ISI, Sept. 1981. - - [5] Postel, Jon, "User Datagram Protocol," Network Working Group - RFC-768/STD-6, ISI, Aug. 1980. - - [6] Postel, Jon, "Transmission Control Protocol," Network Working - Group RFC-793/STD-7, ISI, Sept. 1981. - - [7] Rijsinghani, A., "Computation of the Internet Checksum via - Incremental Update," Network Working Group RFC-1624, Digital - Equipment Corp., May 1994. - - [8] Touch, J., "PC-ATOMIC", ISI Tech. Report. SR-95-407, June 1995. - - - - -Touch & Parham Informational [Page 8] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -Authors' Addresses - - Joe Touch - University of Southern California/Information Sciences Institute - 4676 Admiralty Way - Marina del Rey, CA 90292-6695 - USA - Phone: +1 310-822-1511 x151 - Fax: +1 310-823-6714 - URL: http://www.isi.edu/~touch - EMail: touch@isi.edu - - - Bruce Parham - University of Southern California/Information Sciences Institute - 4676 Admiralty Way - Marina del Rey, CA 90292-6695 - USA - Phone: +1 310-822-1511 x101 - Fax: +1 310-823-6714 - EMail: bparham@isi.edu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Touch & Parham Informational [Page 9] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -Appendix A: PLD source code - -The following is the PLD source code for an AMD MACH-435 PLD. The -MACH-435 is composed of 8 22V10-equivalent PLD blocks, connected by a -configurable internal matrix. - - ----- (PLD source code follows) ---- - -TITLE PC-ATOMIC IP Sum Accelerator - 1-clock 2- and 3-bit 26 ns version -PATTERN ip_sum -REVISION 1.01 -AUTHOR J. Touch & B. Parham -COMPANY USC/ISI -DATE 06/21/94 - -CHIP ip_sum MACH435 - -; accumulates in 1 clock (1 level of logic) -; -; resources allocated to reduce fitting time -; -; uses an input register "dl" to latch the data bus values on rising edge -; accumulates a hi/lo ones-complement sum in register "q" -; the input and output are accessed via bidirectional pins "dq" -; -; uses 2 groups of 6 carry bit registers "cy" -; -; use 3-bit full-adders with carry lookahead (settles in 6 clocks) -; group 16 bits as [000102 030405 0607 080910 111213 1415] -; [161718 192021 2223 242526 272829 3031] -; -; locking the pins down speeds up fitting and is designed to force -; 4-bit components into single "segments" of the PLD. -; we could have indicated the same thing via: -; GROUP MACH_SEG_A dq[6..0] -; GROUP MACH_SEG_B dq[14..8] -; GROUP MACH_SEG_C dq[22..16] -; GROUP MACH_SEG_D dq[30..24] - -; -; control pins: -; -PIN 20 clk ; adder clock -PIN 62 ip_add ; add current data to sum -PIN 83 ip_sum_ena ; output current sum -PIN 41 ip_clr ; clear current sum -PIN 23 ip_dclk ; input data latch (tied to clk, or not) - - - -Touch & Parham Informational [Page 10] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; dq are data bus pins -; dl is the input register -; -PIN [9..3] dq[6..0] IPAIR dl[6..0] ; IO port -PIN [18..12] dq[14..8] IPAIR dl[14..8] ; IO port -PIN [30..24] dq[22..16] IPAIR dl[22..16] ; IO port -PIN [39..33] dq[30..24] IPAIR dl[30..24] ; IO port -PIN ? dq[31,23,15,7] IPAIR dl[31,23,15,7] ; IO port - -; -; q is the partial checksum register -; dl is the input register -; dq are the data bus pins -; -NODE ? q[31..0] OPAIR dq[31..0] ; internal data in reg -NODE ? dl[31..0] REG ; input reg - -; -; cy are the carry register bits -; -NODE ? cy[31,29,26,23,21,18,15,13,10,7,5,2] REG - ;1-bit internal carry bits - -EQUATIONS - -; -; .trst is the tri-state control, 0 means these are always inputs -; -ip_add.trst = 0 -ip_clr.trst = 0 -ip_sum_ena.trst = 0 - -; -; grab data to the input register on every clock (irrelevant if invalid) -; -dl[31..0].clkf = ip_dclk ; grab data all the time - ; don't use setf, rstf, or trst for dl - ; we want dl to map to input registers, not internal cells - ; besides, input registers don't need setf, rstf, or trst - -; -; control of the checksum register -; -dq[31..0].clkf = clk ; clk clocks everything -dq[31..0].setf = gnd ; never preset registers -dq[31..0].rstf = ip_clr ; clear on reset -dq[31..0].trst = ip_sum_ena ; ena outputs sum - read - - - -Touch & Parham Informational [Page 11] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; control for the carry register -; -cy[31,29,26,23,21,18,15,13,10,7,5,2].clkf = clk -cy[31,29,26,23,21,18,15,13,10,7,5,2].setf = gnd ; never preset -cy[31,29,26,23,21,18,15,13,10,7,5,2].rstf = ip_clr ; clear on reset - -; -; INPUT DATA LATCH -; nothing fancy here - grab all inputs when ip_add signal is high -; i.e., grab data in input register -; -dl[31..0] := dq[31..0] - -; -; COMBINATORIAL ADDER -; -; built as a series of 2-bit and 3-bit (carry-lookahead) full-adders -; with carries sent to the carry register "pipeline" -; -; sum[n] are sum bits -; cy[m] are carry bits -; ":+:" is XOR - -; -; SUM[0] = (A0 :+: B0 :+: CARRY_IN) -; -; CY[0] = ((A0 * B0) + ((A0 :+: B0) * CARRY_IN)) -; -; actually, the latter can be rewritten as -; -; CY[0] = ((A0 * B0) + ((A0 + B0) * CARRY_IN)) -; -; because the XOR won't be invalidated by the AND case, since the -; result is always 1 from the first term then anyway -; this helps reduce the number of XOR terms required, which are -; a limited resource in PLDs -; - - - - - - - - - - - - - -Touch & Parham Informational [Page 12] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; SUM THE LOW-ORDER WORD -; - -; -; the first 5 bits [0..4] of the low-order word -; -q[0] := (q[0] :+: (ip_add * dl[0]) :+: cy[15]) - -q[1] := (q[1] :+: (ip_add * dl[1]) :+: - ((ip_add * - (q[0] * dl[0] + - dl[0] * cy[15])) + - (q[0] * cy[15]))) - -q[2] := (q[2] :+: (ip_add * dl[2]) :+: - ((ip_add * - (q[1] * dl[1] + - q[1] * q[0] * dl[0] + - dl[1] * q[0] * dl[0] + - q[1] * dl[0] * cy[15] + - dl[1] * dl[0] * cy[15] + - dl[1] * q[0] * cy[15])) + - (q[1] * q[0] * cy[15]))) - -cy[2] := ((ip_add * - (q[2] * dl[2] + - q[2] * q[1] * dl[1] + - dl[2] * q[1] * dl[1] + - q[2] * q[1] * q[0] * dl[0] + - q[2] * dl[1] * q[0] * dl[0] + - dl[2] * q[1] * q[0] * dl[0] + - dl[2] * dl[1] * q[0] * dl[0] + - q[2] * q[1] * dl[0] * cy[15] + - q[2] * dl[1] * q[0] * cy[15] + - q[2] * dl[1] * dl[0] * cy[15] + - dl[2] * q[1] * q[0] * cy[15] + - dl[2] * q[1] * dl[0] * cy[15] + - dl[2] * dl[1] * q[0] * cy[15] + - dl[2] * dl[1] * dl[0] * cy[15])) + - (q[2] * q[1] * q[0] * cy[15])) - -q[3] := (q[3] :+: (ip_add * dl[3]) :+: cy[2]) - -q[4] := (q[4] :+: (ip_add * dl[4]) :+: - ((ip_add * - (q[3] * dl[3] + - dl[3] * cy[2])) + - (q[3] * cy[2]))) - - - -Touch & Parham Informational [Page 13] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; the next 3 bits [5..7] of the low-order word -; -q[5] := (q[5] :+: (ip_add * dl[5]) :+: - ((ip_add * - (q[4] * dl[4] + - q[4] * q[3] * dl[3] + - dl[4] * q[3] * dl[3] + - q[4] * dl[3] * cy[2] + - dl[4] * dl[3] * cy[2] + - dl[4] * q[3] * cy[2])) + - (q[4] * q[3] * cy[2]))) - -cy[5] := ((ip_add * ( - q[5] * dl[5] + - q[5] * q[4] * dl[4] + - dl[5] * q[4] * dl[4] + - q[5] * q[4] * q[3] * dl[3] + - q[5] * dl[4] * q[3] * dl[3] + - dl[5] * q[4] * q[3] * dl[3] + - dl[5] * dl[4] * q[3] * dl[3] + - q[5] * q[4] * dl[3] * cy[2] + - q[5] * dl[4] * q[3] * cy[2] + - q[5] * dl[4] * dl[3] * cy[2] + - dl[5] * q[4] * q[3] * cy[2] + - dl[5] * q[4] * dl[3] * cy[2] + - dl[5] * dl[4] * q[3] * cy[2] + - dl[5] * dl[4] * dl[3] * cy[2])) + - (q[5] * q[4] * q[3] * cy[2])) - -q[6] := (q[6] :+: (ip_add * dl[6]) :+: cy[5]) - -q[7] := (q[7] :+: (ip_add * dl[7]) :+: - ((ip_add * - (q[6] * dl[6] + - dl[6] * cy[5])) + - (q[6] * cy[5]))) - -cy[7] := ((ip_add * - (q[7] * dl[7] + - q[7] * q[6] * dl[6] + - dl[7] * q[6] * dl[6] + - q[7] * dl[6] * cy[5] + - dl[7] * dl[6] * cy[5] + - dl[7] * q[6] * cy[5])) + - (q[7] * q[6] * cy[5])) - - - - - -Touch & Parham Informational [Page 14] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; the next 5 bits [8..12] of the low-order word -; -q[8] := (q[8] :+: (ip_add * dl[8]) :+: cy[7]) - -q[9] := (q[9] :+: (ip_add * dl[9]) :+: - ((ip_add * - (q[8] * dl[8] + - dl[8] * cy[7])) + - (q[8] * cy[7]))) - -q[10] := (q[10] :+: (ip_add * dl[10]) :+: - ((ip_add * - (q[9] * dl[9] + - q[9] * q[8] * dl[8] + - dl[9] * q[8] * dl[8] + - q[9] * dl[8] * cy[7] + - dl[9] * dl[8] * cy[7] + - dl[9] * q[8] * cy[7])) + - (q[9] * q[8] * cy[7]))) - -cy[10] := ((ip_add * - (q[10] * dl[10] + - q[10] * q[9] * dl[9] + - dl[10] * q[9] * dl[9] + - q[10] * q[9] * q[8] * dl[8] + - q[10] * dl[9] * q[8] * dl[8] + - dl[10] * q[9] * q[8] * dl[8] + - dl[10] * dl[9] * q[8] * dl[8] + - q[10] * q[9] * dl[8] * cy[7] + - q[10] * dl[9] * q[8] * cy[7] + - q[10] * dl[9] * dl[8] * cy[7] + - dl[10] * q[9] * q[8] * cy[7] + - dl[10] * q[9] * dl[8] * cy[7] + - dl[10] * dl[9] * q[8] * cy[7] + - dl[10] * dl[9] * dl[8] * cy[7])) + - (q[10] * q[9] * q[8] * cy[7])) - -q[11] := (q[11] :+: (ip_add * dl[11]) :+: cy[10]) - -q[12] := (q[12] :+: (ip_add * dl[12]) :+: - ((ip_add * - (q[11] * dl[11] + - dl[11] * cy[10])) + - (q[11] * cy[10]))) - - - - - - -Touch & Parham Informational [Page 15] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; the final 3 bits [13..15] of the low-order word -; -q[13] := (q[13] :+: (ip_add * dl[13]) :+: - ((ip_add * - (q[12] * dl[12] + - q[12] * q[11] * dl[11] + - dl[12] * q[11] * dl[11] + - q[12] * dl[11] * cy[10] + - dl[12] * dl[11] * cy[10] + - dl[12] * q[11] * cy[10])) + - (q[12] * q[11] * cy[10]))) - -cy[13] := ((ip_add * ( - q[13] * dl[13] + - q[13] * q[12] * dl[12] + - dl[13] * q[12] * dl[12] + - q[13] * q[12] * q[11] * dl[11] + - q[13] * dl[12] * q[11] * dl[11] + - dl[13] * q[12] * q[11] * dl[11] + - dl[13] * dl[12] * q[11] * dl[11] + - q[13] * q[12] * dl[11] * cy[10] + - q[13] * dl[12] * q[11] * cy[10] + - q[13] * dl[12] * dl[11] * cy[10] + - dl[13] * q[12] * q[11] * cy[10] + - dl[13] * q[12] * dl[11] * cy[10] + - dl[13] * dl[12] * q[11] * cy[10] + - dl[13] * dl[12] * dl[11] * cy[10])) + - (q[13] * q[12] * q[11] * cy[10])) - -q[14] := (q[14] :+: (ip_add * dl[14]) :+: cy[13]) - -q[15] := (q[15] :+: (ip_add * dl[15]) :+: - ((ip_add * - (q[14] * dl[14] + - dl[14] * cy[13])) + - (q[14] * cy[13]))) - -cy[15] := ((ip_add * - (q[15] * dl[15] + - q[15] * q[14] * dl[14] + - dl[15] * q[14] * dl[14] + - q[15] * dl[14] * cy[13] + - dl[15] * dl[14] * cy[13] + - dl[15] * q[14] * cy[13])) + - (q[15] * q[14] * cy[13])) - - - - - -Touch & Parham Informational [Page 16] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; SUM THE HIGH-ORDER WORD -; - -; -; the first 5 bits [16..20] of the high-order word -; -q[16] := (q[16] :+: (ip_add * dl[16]) :+: cy[31]) - -q[17] := (q[17] :+: (ip_add * dl[17]) :+: - ((ip_add * - (q[16] * dl[16] + - dl[16] * cy[31])) + - (q[16] * cy[31]))) - -q[18] := (q[18] :+: (ip_add * dl[18]) :+: - ((ip_add * - (q[17] * dl[17] + - q[17] * q[16] * dl[16] + - dl[17] * q[16] * dl[16] + - q[17] * dl[16] * cy[31] + - dl[17] * dl[16] * cy[31] + - dl[17] * q[16] * cy[31])) + - (q[17] * q[16] * cy[31]))) - -cy[18] := ((ip_add * - (q[18] * dl[18] + - q[18] * q[17] * dl[17] + - dl[18] * q[17] * dl[17] + - q[18] * q[17] * q[16] * dl[16] + - q[18] * dl[17] * q[16] * dl[16] + - dl[18] * q[17] * q[16] * dl[16] + - dl[18] * dl[17] * q[16] * dl[16] + - q[18] * q[17] * dl[16] * cy[31] + - q[18] * dl[17] * q[16] * cy[31] + - q[18] * dl[17] * dl[16] * cy[31] + - dl[18] * q[17] * q[16] * cy[31] + - dl[18] * q[17] * dl[16] * cy[31] + - dl[18] * dl[17] * q[16] * cy[31] + - dl[18] * dl[17] * dl[16] * cy[31])) + - (q[18] * q[17] * q[16] * cy[31])) - -q[19] := (q[19] :+: (ip_add * dl[19]) :+: cy[18]) - -q[20] := (q[20] :+: (ip_add * dl[20]) :+: - ((ip_add * - (q[19] * dl[19] + - dl[19] * cy[18])) + - (q[19] * cy[18]))) - - - -Touch & Parham Informational [Page 17] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; the next 3 bits [21..23] of the high-order word -; -q[21] := (q[21] :+: (ip_add * dl[21]) :+: - ((ip_add * - (q[20] * dl[20] + - q[20] * q[19] * dl[19] + - dl[20] * q[19] * dl[19] + - q[20] * dl[19] * cy[18] + - dl[20] * dl[19] * cy[18] + - dl[20] * q[19] * cy[18])) + - (q[20] * q[19] * cy[18]))) - -cy[21] := ((ip_add * ( - q[21] * dl[21] + - q[21] * q[20] * dl[20] + - dl[21] * q[20] * dl[20] + - q[21] * q[20] * q[19] * dl[19] + - q[21] * dl[20] * q[19] * dl[19] + - dl[21] * q[20] * q[19] * dl[19] + - dl[21] * dl[20] * q[19] * dl[19] + - q[21] * q[20] * dl[19] * cy[18] + - q[21] * dl[20] * q[19] * cy[18] + - q[21] * dl[20] * dl[19] * cy[18] + - dl[21] * q[20] * q[19] * cy[18] + - dl[21] * q[20] * dl[19] * cy[18] + - dl[21] * dl[20] * q[19] * cy[18] + - dl[21] * dl[20] * dl[19] * cy[18])) + - (q[21] * q[20] * q[19] * cy[18])) - -q[22] := (q[22] :+: (ip_add * dl[22]) :+: cy[21]) - -q[23] := (q[23] :+: (ip_add * dl[23]) :+: - ((ip_add * - (q[22] * dl[22] + - dl[22] * cy[21])) + - (q[22] * cy[21]))) - -cy[23] := ((ip_add * - (q[23] * dl[23] + - q[23] * q[22] * dl[22] + - dl[23] * q[22] * dl[22] + - q[23] * dl[22] * cy[21] + - dl[23] * dl[22] * cy[21] + - dl[23] * q[22] * cy[21])) + - (q[23] * q[22] * cy[21])) - - - - - -Touch & Parham Informational [Page 18] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; the next 5 bits [24..28] of the high-order word -; -q[24] := (q[24] :+: (ip_add * dl[24]) :+: cy[23]) - -q[25] := (q[25] :+: (ip_add * dl[25]) :+: - ((ip_add * - (q[24] * dl[24] + - dl[24] * cy[23])) + - (q[24] * cy[23]))) - -q[26] := (q[26] :+: (ip_add * dl[26]) :+: - ((ip_add * - (q[25] * dl[25] + - q[25] * q[24] * dl[24] + - dl[25] * q[24] * dl[24] + - q[25] * dl[24] * cy[23] + - dl[25] * dl[24] * cy[23] + - dl[25] * q[24] * cy[23])) + - (q[25] * q[24] * cy[23]))) - -cy[26] := ((ip_add * - (q[26] * dl[26] + - q[26] * q[25] * dl[25] + - dl[26] * q[25] * dl[25] + - q[26] * q[25] * q[24] * dl[24] + - q[26] * dl[25] * q[24] * dl[24] + - dl[26] * q[25] * q[24] * dl[24] + - dl[26] * dl[25] * q[24] * dl[24] + - q[26] * q[25] * dl[24] * cy[23] + - q[26] * dl[25] * q[24] * cy[23] + - q[26] * dl[25] * dl[24] * cy[23] + - dl[26] * q[25] * q[24] * cy[23] + - dl[26] * q[25] * dl[24] * cy[23] + - dl[26] * dl[25] * q[24] * cy[23] + - dl[26] * dl[25] * dl[24] * cy[23])) + - (q[26] * q[25] * q[24] * cy[23])) - -q[27] := (q[27] :+: (ip_add * dl[27]) :+: cy[26]) - -q[28] := (q[28] :+: (ip_add * dl[28]) :+: - ((ip_add * - (q[27] * dl[27] + - dl[27] * cy[26])) + - (q[27] * cy[26]))) - - - - - - -Touch & Parham Informational [Page 19] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; the final 3 bits [29..31] of the high-order word -; -q[29] := (q[29] :+: (ip_add * dl[29]) :+: - ((ip_add * - (q[28] * dl[28] + - q[28] * q[27] * dl[27] + - dl[28] * q[27] * dl[27] + - q[28] * dl[27] * cy[26] + - dl[28] * dl[27] * cy[26] + - dl[28] * q[27] * cy[26])) + - (q[28] * q[27] * cy[26]))) - -cy[29] := ((ip_add * ( - q[29] * dl[29] + - q[29] * q[28] * dl[28] + - dl[29] * q[28] * dl[28] + - q[29] * q[28] * q[27] * dl[27] + - q[29] * dl[28] * q[27] * dl[27] + - dl[29] * q[28] * q[27] * dl[27] + - dl[29] * dl[28] * q[27] * dl[27] + - q[29] * q[28] * dl[27] * cy[26] + - q[29] * dl[28] * q[27] * cy[26] + - q[29] * dl[28] * dl[27] * cy[26] + - dl[29] * q[28] * q[27] * cy[26] + - dl[29] * q[28] * dl[27] * cy[26] + - dl[29] * dl[28] * q[27] * cy[26] + - dl[29] * dl[28] * dl[27] * cy[26])) + - (q[29] * q[28] * q[27] * cy[26])) - -q[30] := (q[30] :+: (ip_add * dl[30]) :+: cy[29]) - -q[31] := (q[31] :+: (ip_add * dl[31]) :+: - ((ip_add * - (q[30] * dl[30] + - dl[30] * cy[29])) + - (q[30] * cy[29]))) - -cy[31] := ((ip_add * - (q[31] * dl[31] + - q[31] * q[30] * dl[30] + - dl[31] * q[30] * dl[30] + - q[31] * dl[30] * cy[29] + - dl[31] * dl[30] * cy[29] + - dl[31] * q[30] * cy[29])) + - (q[31] * q[30] * cy[29])) - - - - - -Touch & Parham Informational [Page 20] - -RFC 1936 Implementing the Internet Checksum in Hardware April 1996 - - -; -; output nodes onto output pins (pending enable..) -; -dq[0] := {q[0]} -dq[1] := {q[1]} -dq[2] := {q[2]} -dq[3] := {q[3]} -dq[4] := {q[4]} -dq[5] := {q[5]} -dq[6] := {q[6]} -dq[7] := {q[7]} -dq[8] := {q[8]} -dq[9] := {q[9]} -dq[10] := {q[10]} -dq[11] := {q[11]} -dq[12] := {q[12]} -dq[13] := {q[13]} -dq[14] := {q[14]} -dq[15] := {q[15]} - -dq[16] := {q[16]} -dq[17] := {q[17]} -dq[18] := {q[18]} -dq[19] := {q[19]} -dq[20] := {q[20]} -dq[21] := {q[21]} -dq[22] := {q[22]} -dq[23] := {q[23]} -dq[24] := {q[24]} -dq[25] := {q[25]} -dq[26] := {q[26]} -dq[27] := {q[27]} -dq[28] := {q[28]} -dq[29] := {q[29]} -dq[30] := {q[30]} -dq[31] := {q[31]} - -; -; end. -; - - - - - - - - - - - -Touch & Parham Informational [Page 21] - diff --git a/ext/picotcp/RFC/rfc1948.txt b/ext/picotcp/RFC/rfc1948.txt deleted file mode 100644 index f660b4f..0000000 --- a/ext/picotcp/RFC/rfc1948.txt +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - -Network Working Group S. Bellovin -Request for Comments: 1948 AT&T Research -Category: Informational May 1996 - - - Defending Against Sequence Number Attacks - -Status of This Memo - - This memo provides information for the Internet community. This memo - does not specify an Internet standard of any kind. Distribution of - this memo is unlimited. - -Abstract - - IP spoofing attacks based on sequence number spoofing have become a - serious threat on the Internet (CERT Advisory CA-95:01). While - ubiquitous crypgraphic authentication is the right answer, we propose - a simple modification to TCP implementations that should be a very - substantial block to the current wave of attacks. - -Overview and Rational - - In 1985, Morris [1] described a form of attack based on guessing what - sequence numbers TCP [2] will use for new connections. Briefly, the - attacker gags a host trusted by the target, impersonates the IP - address of the trusted host when talking to the target, and completes - the 3-way handshake based on its guess at the next initial sequence - number to be used. An ordinary connection to the target is used to - gather sequence number state information. This entire sequence, - coupled with address-based authentication, allows the attacker to - execute commands on the target host. - - Clearly, the proper solution is cryptographic authentication [3,4]. - But it will quite a long time before that is deployed. It has - therefore been necessary for many sites to restrict use of protocols - that rely on address-based authentication, such as rlogin and rsh. - Unfortunately, the prevalence of "sniffer attacks" -- network - eavesdropping (CERT Advisory CA-94:01) -- has rendered ordinary - TELNET [5] very dangerous as well. The Internet is thus left without - a safe, secure mechanism for remote login. - - We propose a simple change to TCP implementations that will block - most sequence number guessing attacks. More precisely, such attacks - will remain possible if and only if the Bad Guy already has the - ability to launch even more devastating attacks. - - - - - -Bellovin Informational [Page 1] - -RFC 1948 Sequence Number Attacks May 1996 - - -Details of the Attack - - In order to understand the particular case of sequence number - guessing, one must look at the 3-way handshake used in the TCP open - sequence [2]. Suppose client machine A wants to talk to rsh server - B. It sends the following message: - - A->B: SYN, ISNa - - That is, it sends a packet with the SYN ("synchronize sequence - number") bit set and an initial sequence number ISNa. - - B replies with - - B->A: SYN, ISNb, ACK(ISNa) - - In addition to sending its own initial sequence number, it - acknowledges A's. Note that the actual numeric value ISNa must - appear in the message. - - A concludes the handshake by sending - - A->B: ACK(ISNb) - - The initial sequence numbers are intended to be more or less random. - More precisely, RFC 793 specifies that the 32-bit counter be - incremented by 1 in the low-order position about every 4 - microseconds. Instead, Berkeley-derived kernels increment it by a - constant every second, and by another constant for each new - connection. Thus, if you open a connection to a machine, you know to - a very high degree of confidence what sequence number it will use for - its next connection. And therein lies the attack. - - The attacker X first opens a real connection to its target B -- say, - to the mail port or the TCP echo port. This gives ISNb. It then - impersonates A and sends - - Ax->B: SYN, ISNx - - where "Ax" denotes a packet sent by X pretending to be A. - - B's response to X's original SYN (so to speak) - - B->A: SYN, ISNb', ACK(ISNx) - - - - - - - -Bellovin Informational [Page 2] - -RFC 1948 Sequence Number Attacks May 1996 - - - goes to the legitimate A, about which more anon. X never sees that - message but can still send - - Ax->B: ACK(ISNb') - - using the predicted value for ISNb'. If the guess is right -- and - usually it will be -- B's rsh server thinks it has a legitimate - connection with A, when in fact X is sending the packets. X can't - see the output from this session, but it can execute commands as more - or less any user -- and in that case, the game is over and X has won. - - There is a minor difficulty here. If A sees B's message, it will - realize that B is acknowledging something it never sent, and will - send a RST packet in response to tear down the connection. There are - a variety of ways to prevent this; the easiest is to wait until the - real A is down (possibly as a result of enemy action, of course). In - actual practice, X can gag A by exploiting a very common - implementation bug; this is described below. - -The Fix - - The choice of initial sequence numbers for a connection is not - random. Rather, it must be chosen so as to minimize the probability - of old stale packets being accepted by new incarnations of the same - connection [6, Appendix A]. Furthermore, implementations of TCP - derived from 4.2BSD contain special code to deal with such - reincarnations when the server end of the original connection is - still in TIMEWAIT state [7, pp. 945]. Accordingly, simple - randomization, as suggested in [8], will not work well. - - But duplicate packets, and hence the restrictions on the initial - sequence number for reincarnations, are peculiar to individual - connections. That is, there is no connection, syntactic or semantic, - between the sequence numbers used for two different connections. We - can prevent sequence number guessing attacks by giving each - connection -- that is, each 4-tuple of -- a separate sequence number space. Within - each space, the initial sequence number is incremented according to - [2]; however, there is no obvious relationship between the numbering - in different spaces. - - The obvious way to do this is to maintain state for dead connections, - and the easiest way to do that is to change the TCP state transition - diagram so that both ends of all connections go to TIMEWAIT state. - That would work, but it's inelegant and consumes storage space. - Instead, we use the current 4 microsecond timer M and set - - ISN = M + F(localhost, localport, remotehost, remoteport). - - - -Bellovin Informational [Page 3] - -RFC 1948 Sequence Number Attacks May 1996 - - - It is vital that F not be computable from the outside, or an attacker - could still guess at sequence numbers from the initial sequence - number used for some other connection. We therefore suggest that F - be a cryptographic hash function of the connection-id and some secret - data. MD5 [9] is a good choice, since the code is widely available. - The secret data can either be a true random number [10], or it can be - the combination of some per-host secret and the boot time of the - machine. The boot time is included to ensure that the secret is - changed on occasion. Other data, such as the host's IP address and - name, may be included in the hash as well; this eases administration - by permitting a network of workstations to share the same secret data - while still giving them separate sequence number spaces. Our - recommendation, in fact, is to use all three of these items: as - random a number as the hardware can generate, an administratively- - installed pass phrase, and the machine's IP address. This allows for - local choice on how secure the secret is. - - Note that the secret cannot easily be changed on a live machine. - Doing so would change the initial sequence numbers used for - reincarnated connections; to maintain safety, either dead connection - state must be kept or a quiet time observed for two maximum segment - lifetimes after such a change. - -A Common TCP Bug - - As mentioned earlier, attackers using sequence number guessing have - to "gag" the trusted machine first. While a number of strategies are - possible, most of the attacks detected thus far rely on an - implementation bug. - - When SYN packets are received for a connection, the receiving system - creates a new TCB in SYN-RCVD state. To avoid overconsumption of - resources, 4.2BSD-derived systems permit only a limited number of - TCBs in this state per connection. Once this limit is reached, - future SYN packets for new connections are discarded; it is assumed - that the client will retransmit them as needed. - - When a packet is received, the first thing that must be done is a - search for the TCB for that connection. If no TCB is found, the - kernel searches for a "wild card" TCB used by servers to accept - connections from all clients. Unfortunately, in many kernels this - code is invoked for any incoming packets, not just for initial SYN - packets. If the SYN-RCVD queue is full for the wildcard TCB, any new - packets specifying just that host and port number will be discarded, - even if they aren't SYN packets. - - - - - - -Bellovin Informational [Page 4] - -RFC 1948 Sequence Number Attacks May 1996 - - - To gag a host, then, the attacker sends a few dozen SYN packets to - the rlogin port from different port numbers on some non-existent - machine. This fills up the SYN-RCVD queue, while the SYN+ACK packets - go off to the bit bucket. The attack on the target machine then - appears to come from the rlogin port on the trusted machine. The - replies -- the SYN+ACKs from the target -- will be perceived as - packets belonging to a full queue, and will be dropped silently. - This could be avoided if the full queue code checked for the ACK bit, - which cannot legally be on for legitimate open requests. If it is - on, RST should be sent in reply. - -Security Considerations - - Good sequence numbers are not a replacement for cryptographic - authentication. At best, they're a palliative measure. - - An eavesdropper who can observe the initial messages for a connection - can determine its sequence number state, and may still be able to - launch sequence number guessing attacks by impersonating that - connection. However, such an eavesdropper can also hijack existing - connections [11], so the incremental threat isn't that high. Still, - since the offset between a fake connection and a given real - connection will be more or less constant for the lifetime of the - secret, it is important to ensure that attackers can never capture - such packets. Typical attacks that could disclose them include both - eavesdropping and the variety of routing attacks discussed in [8]. - - If random numbers are used as the sole source of the secret, they - MUST be chosen in accordance with the recommendations given in [10]. - -Acknowledgments - - Matt Blaze and Jim Ellis contributed some crucial ideas to this RFC. - Frank Kastenholz contributed constructive comments to this memo. - -References - - [1] R.T. Morris, "A Weakness in the 4.2BSD UNIX TCP/IP Software", - CSTR 117, 1985, AT&T Bell Laboratories, Murray Hill, NJ. - - [2] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, - September 1981. - - [3] Kohl, J., and C. Neuman, "The Kerberos Network Authentication - Service (V5)", RFC 1510, September 1993. - - [4] Atkinson, R., "Security Architecture for the Internet - Protocol", RFC 1825, August 1995. - - - -Bellovin Informational [Page 5] - -RFC 1948 Sequence Number Attacks May 1996 - - - [5] Postel, J., and J. Reynolds, "Telnet Protocol Specification", - STD 8, RFC 854, May 1983. - - [6] Jacobson, V., Braden, R., and L. Zhang, "TCP Extension for - High-Speed Paths", RFC 1885, October 1990. - - [7] G.R. Wright, W. R. Stevens, "TCP/IP Illustrated, Volume 2", - 1995. Addison-Wesley. - - [8] S. Bellovin, "Security Problems in the TCP/IP Protocol Suite", - April 1989, Computer Communications Review, vol. 19, no. 2, pp. - 32-48. - - [9] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, - April 1992. - - [10] Eastlake, D., Crocker, S., and J. Schiller, "Randomness - Recommendations for Security", RFC 1750, December 1994. - - [11] L. Joncheray, "A Simple Active Attack Against TCP, 1995, Proc. - Fifth Usenix UNIX Security Symposium. - -Author's Address - - Steven M. Bellovin - AT&T Research - 600 Mountain Avenue - Murray Hill, NJ 07974 - - Phone: (908) 582-5886 - EMail: smb@research.att.com - - - - - - - - - - - - - - - - - - - - -Bellovin Informational [Page 6] - diff --git a/ext/picotcp/RFC/rfc1994.txt b/ext/picotcp/RFC/rfc1994.txt deleted file mode 100644 index e4a553e..0000000 --- a/ext/picotcp/RFC/rfc1994.txt +++ /dev/null @@ -1,732 +0,0 @@ - - - - - - -Network Working Group W. Simpson -Request for Comments: 1994 DayDreamer -Obsoletes: 1334 August 1996 -Category: Standards Track - - - PPP Challenge Handshake Authentication Protocol (CHAP) - - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Abstract - - The Point-to-Point Protocol (PPP) [1] provides a standard method for - transporting multi-protocol datagrams over point-to-point links. - - PPP also defines an extensible Link Control Protocol, which allows - negotiation of an Authentication Protocol for authenticating its peer - before allowing Network Layer protocols to transmit over the link. - - This document defines a method for Authentication using PPP, which - uses a random Challenge, with a cryptographically hashed Response - which depends upon the Challenge and a secret key. - -Table of Contents - - 1. Introduction .......................................... 1 - 1.1 Specification of Requirements ................... 1 - 1.2 Terminology ..................................... 2 - 2. Challenge-Handshake Authentication Protocol ........... 2 - 2.1 Advantages ...................................... 3 - 2.2 Disadvantages ................................... 3 - 2.3 Design Requirements ............................. 4 - 3. Configuration Option Format ........................... 5 - 4. Packet Format ......................................... 6 - 4.1 Challenge and Response .......................... 7 - 4.2 Success and Failure ............................. 9 - SECURITY CONSIDERATIONS ...................................... 10 - ACKNOWLEDGEMENTS ............................................. 11 - REFERENCES ................................................... 12 - CONTACTS ..................................................... 12 - - - - -Simpson [Page i] - -RFC 1994 PPP CHAP August 1996 - - -1. Introduction - - In order to establish communications over a point-to-point link, each - end of the PPP link must first send LCP packets to configure the data - link during Link Establishment phase. After the link has been - established, PPP provides for an optional Authentication phase before - proceeding to the Network-Layer Protocol phase. - - By default, authentication is not mandatory. If authentication of - the link is desired, an implementation MUST specify the - Authentication-Protocol Configuration Option during Link - Establishment phase. - - These authentication protocols are intended for use primarily by - hosts and routers that connect to a PPP network server via switched - circuits or dial-up lines, but might be applied to dedicated links as - well. The server can use the identification of the connecting host - or router in the selection of options for network layer negotiations. - - This document defines a PPP authentication protocol. The Link - Establishment and Authentication phases, and the Authentication- - Protocol Configuration Option, are defined in The Point-to-Point - Protocol (PPP) [1]. - - -1.1. Specification of Requirements - - In this document, several words are used to signify the requirements - of the specification. These words are often capitalized. - - MUST This word, or the adjective "required", means that the - definition is an absolute requirement of the specification. - - MUST NOT This phrase means that the definition is an absolute - prohibition of the specification. - - SHOULD This word, or the adjective "recommended", means that there - may exist valid reasons in particular circumstances to - ignore this item, but the full implications must be - understood and carefully weighed before choosing a - different course. - - MAY This word, or the adjective "optional", means that this - item is one of an allowed set of alternatives. An - implementation which does not include this option MUST be - prepared to interoperate with another implementation which - does include the option. - - - - -Simpson [Page 1] - -RFC 1994 PPP CHAP August 1996 - - -1.2. Terminology - - This document frequently uses the following terms: - - authenticator - The end of the link requiring the authentication. The - authenticator specifies the authentication protocol to be - used in the Configure-Request during Link Establishment - phase. - - peer The other end of the point-to-point link; the end which is - being authenticated by the authenticator. - - silently discard - This means the implementation discards the packet without - further processing. The implementation SHOULD provide the - capability of logging the error, including the contents of - the silently discarded packet, and SHOULD record the event - in a statistics counter. - - - - -2. Challenge-Handshake Authentication Protocol - - The Challenge-Handshake Authentication Protocol (CHAP) is used to - periodically verify the identity of the peer using a 3-way handshake. - This is done upon initial link establishment, and MAY be repeated - anytime after the link has been established. - - 1. After the Link Establishment phase is complete, the - authenticator sends a "challenge" message to the peer. - - 2. The peer responds with a value calculated using a "one-way - hash" function. - - 3. The authenticator checks the response against its own - calculation of the expected hash value. If the values match, - the authentication is acknowledged; otherwise the connection - SHOULD be terminated. - - 4. At random intervals, the authenticator sends a new challenge to - the peer, and repeats steps 1 to 3. - - - - - - - - -Simpson [Page 2] - -RFC 1994 PPP CHAP August 1996 - - -2.1. Advantages - - CHAP provides protection against playback attack by the peer through - the use of an incrementally changing identifier and a variable - challenge value. The use of repeated challenges is intended to limit - the time of exposure to any single attack. The authenticator is in - control of the frequency and timing of the challenges. - - This authentication method depends upon a "secret" known only to the - authenticator and that peer. The secret is not sent over the link. - - Although the authentication is only one-way, by negotiating CHAP in - both directions the same secret set may easily be used for mutual - authentication. - - Since CHAP may be used to authenticate many different systems, name - fields may be used as an index to locate the proper secret in a large - table of secrets. This also makes it possible to support more than - one name/secret pair per system, and to change the secret in use at - any time during the session. - - -2.2. Disadvantages - - CHAP requires that the secret be available in plaintext form. - Irreversably encrypted password databases commonly available cannot - be used. - - It is not as useful for large installations, since every possible - secret is maintained at both ends of the link. - - Implementation Note: To avoid sending the secret over other links - in the network, it is recommended that the challenge and response - values be examined at a central server, rather than each network - access server. Otherwise, the secret SHOULD be sent to such - servers in a reversably encrypted form. Either case requires a - trusted relationship, which is outside the scope of this - specification. - - - - - - - - - - - - - -Simpson [Page 3] - -RFC 1994 PPP CHAP August 1996 - - -2.3. Design Requirements - - The CHAP algorithm requires that the length of the secret MUST be at - least 1 octet. The secret SHOULD be at least as large and - unguessable as a well-chosen password. It is preferred that the - secret be at least the length of the hash value for the hashing - algorithm chosen (16 octets for MD5). This is to ensure a - sufficiently large range for the secret to provide protection against - exhaustive search attacks. - - The one-way hash algorithm is chosen such that it is computationally - infeasible to determine the secret from the known challenge and - response values. - - Each challenge value SHOULD be unique, since repetition of a - challenge value in conjunction with the same secret would permit an - attacker to reply with a previously intercepted response. Since it - is expected that the same secret MAY be used to authenticate with - servers in disparate geographic regions, the challenge SHOULD exhibit - global and temporal uniqueness. - - Each challenge value SHOULD also be unpredictable, least an attacker - trick a peer into responding to a predicted future challenge, and - then use the response to masquerade as that peer to an authenticator. - - Although protocols such as CHAP are incapable of protecting against - realtime active wiretapping attacks, generation of unique - unpredictable challenges can protect against a wide range of active - attacks. - - A discussion of sources of uniqueness and probability of divergence - is included in the Magic-Number Configuration Option [1]. - - - - - - - - - - - - - - - - - - - -Simpson [Page 4] - -RFC 1994 PPP CHAP August 1996 - - -3. Configuration Option Format - - A summary of the Authentication-Protocol Configuration Option format - to negotiate the Challenge-Handshake Authentication Protocol is shown - below. The fields are transmitted from left to right. - - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Authentication-Protocol | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Algorithm | - +-+-+-+-+-+-+-+-+ - - Type - - 3 - - Length - - 5 - - Authentication-Protocol - - c223 (hex) for Challenge-Handshake Authentication Protocol. - - Algorithm - - The Algorithm field is one octet and indicates the authentication - method to be used. Up-to-date values are specified in the most - recent "Assigned Numbers" [2]. One value is required to be - implemented: - - 5 CHAP with MD5 [3] - - - - - - - - - - - - - - - - - - - -Simpson [Page 5] - -RFC 1994 PPP CHAP August 1996 - - -4. Packet Format - - Exactly one Challenge-Handshake Authentication Protocol packet is - encapsulated in the Information field of a PPP Data Link Layer frame - where the protocol field indicates type hex c223 (Challenge-Handshake - Authentication Protocol). A summary of the CHAP packet format is - shown below. The fields are transmitted from left to right. - - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data ... - +-+-+-+-+ - - Code - - The Code field is one octet and identifies the type of CHAP - packet. CHAP Codes are assigned as follows: - - 1 Challenge - 2 Response - 3 Success - 4 Failure - - Identifier - - The Identifier field is one octet and aids in matching challenges, - responses and replies. - - Length - - The Length field is two octets and indicates the length of the - CHAP packet including the Code, Identifier, Length and Data - fields. Octets outside the range of the Length field should be - treated as Data Link Layer padding and should be ignored on - reception. - - Data - - The Data field is zero or more octets. The format of the Data - field is determined by the Code field. - - - - - - - - - - -Simpson [Page 6] - -RFC 1994 PPP CHAP August 1996 - - -4.1. Challenge and Response - - Description - - The Challenge packet is used to begin the Challenge-Handshake - Authentication Protocol. The authenticator MUST transmit a CHAP - packet with the Code field set to 1 (Challenge). Additional - Challenge packets MUST be sent until a valid Response packet is - received, or an optional retry counter expires. - - A Challenge packet MAY also be transmitted at any time during the - Network-Layer Protocol phase to ensure that the connection has not - been altered. - - The peer SHOULD expect Challenge packets during the Authentication - phase and the Network-Layer Protocol phase. Whenever a Challenge - packet is received, the peer MUST transmit a CHAP packet with the - Code field set to 2 (Response). - - Whenever a Response packet is received, the authenticator compares - the Response Value with its own calculation of the expected value. - Based on this comparison, the authenticator MUST send a Success or - Failure packet (described below). - - Implementation Notes: Because the Success might be lost, the - authenticator MUST allow repeated Response packets during the - Network-Layer Protocol phase after completing the - Authentication phase. To prevent discovery of alternative - Names and Secrets, any Response packets received having the - current Challenge Identifier MUST return the same reply Code - previously returned for that specific Challenge (the message - portion MAY be different). Any Response packets received - during any other phase MUST be silently discarded. - - When the Failure is lost, and the authenticator terminates the - link, the LCP Terminate-Request and Terminate-Ack provide an - alternative indication that authentication failed. - - - - - - - - - - - - - - -Simpson [Page 7] - -RFC 1994 PPP CHAP August 1996 - - - A summary of the Challenge and Response packet format is shown below. - The fields are transmitted from left to right. - - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Value-Size | Value ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Name ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Code - - 1 for Challenge; - - 2 for Response. - - Identifier - - The Identifier field is one octet. The Identifier field MUST be - changed each time a Challenge is sent. - - The Response Identifier MUST be copied from the Identifier field - of the Challenge which caused the Response. - - Value-Size - - This field is one octet and indicates the length of the Value - field. - - Value - - The Value field is one or more octets. The most significant octet - is transmitted first. - - The Challenge Value is a variable stream of octets. The - importance of the uniqueness of the Challenge Value and its - relationship to the secret is described above. The Challenge - Value MUST be changed each time a Challenge is sent. The length - of the Challenge Value depends upon the method used to generate - the octets, and is independent of the hash algorithm used. - - The Response Value is the one-way hash calculated over a stream of - octets consisting of the Identifier, followed by (concatenated - with) the "secret", followed by (concatenated with) the Challenge - Value. The length of the Response Value depends upon the hash - algorithm used (16 octets for MD5). - - - - -Simpson [Page 8] - -RFC 1994 PPP CHAP August 1996 - - - Name - - The Name field is one or more octets representing the - identification of the system transmitting the packet. There are - no limitations on the content of this field. For example, it MAY - contain ASCII character strings or globally unique identifiers in - ASN.1 syntax. The Name should not be NUL or CR/LF terminated. - The size is determined from the Length field. - - -4.2. Success and Failure - - Description - - If the Value received in a Response is equal to the expected - value, then the implementation MUST transmit a CHAP packet with - the Code field set to 3 (Success). - - If the Value received in a Response is not equal to the expected - value, then the implementation MUST transmit a CHAP packet with - the Code field set to 4 (Failure), and SHOULD take action to - terminate the link. - - A summary of the Success and Failure packet format is shown below. - The fields are transmitted from left to right. - - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Code | Identifier | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message ... - +-+-+-+-+-+-+-+-+-+-+-+-+- - - Code - - 3 for Success; - - 4 for Failure. - - Identifier - - The Identifier field is one octet and aids in matching requests - and replies. The Identifier field MUST be copied from the - Identifier field of the Response which caused this reply. - - - - - - - - -Simpson [Page 9] - -RFC 1994 PPP CHAP August 1996 - - - Message - - The Message field is zero or more octets, and its contents are - implementation dependent. It is intended to be human readable, - and MUST NOT affect operation of the protocol. It is recommended - that the message contain displayable ASCII characters 32 through - 126 decimal. Mechanisms for extension to other character sets are - the topic of future research. The size is determined from the - Length field. - - - -Security Considerations - - Security issues are the primary topic of this RFC. - - The interaction of the authentication protocols within PPP are highly - implementation dependent. This is indicated by the use of SHOULD - throughout the document. - - For example, upon failure of authentication, some implementations do - not terminate the link. Instead, the implementation limits the kind - of traffic in the Network-Layer Protocols to a filtered subset, which - in turn allows the user opportunity to update secrets or send mail to - the network administrator indicating a problem. - - There is no provision for re-tries of failed authentication. - However, the LCP state machine can renegotiate the authentication - protocol at any time, thus allowing a new attempt. It is recommended - that any counters used for authentication failure not be reset until - after successful authentication, or subsequent termination of the - failed link. - - There is no requirement that authentication be full duplex or that - the same protocol be used in both directions. It is perfectly - acceptable for different protocols to be used in each direction. - This will, of course, depend on the specific protocols negotiated. - - The secret SHOULD NOT be the same in both directions. This allows an - attacker to replay the peer's challenge, accept the computed - response, and use that response to authenticate. - - 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 - - - -Simpson [Page 10] - -RFC 1994 PPP CHAP August 1996 - - - 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. - - Passwords and other secrets should be stored at the respective ends - such that access to them is as limited as possible. Ideally, the - secrets should only be accessible to the process requiring access in - order to perform the authentication. - - The secrets should be distributed with a mechanism that limits the - number of entities that handle (and thus gain knowledge of) the - secret. Ideally, no unauthorized person should ever gain knowledge - of the secrets. Such a mechanism is outside the scope of this - specification. - - -Acknowledgements - - David Kaufman, Frank Heinrich, and Karl Auerbach used a challenge - handshake at SDC when designing one of the protocols for a "secure" - network in the mid-1970s. Tom Bearson built a prototype Sytek - product ("Poloneous"?) on the challenge-response notion in the 1982- - 83 timeframe. Another variant is documented in the various IBM SNA - manuals. Yet another variant was implemented by Karl Auerbach in the - Telebit NetBlazer circa 1991. - - Kim Toms and Barney Wolff provided useful critiques of earlier - versions of this document. - - Special thanks to Dave Balenson, Steve Crocker, James Galvin, and - Steve Kent, for their extensive explanations and suggestions. Now, - if only we could get them to agree with each other. - - - - - - - - - - - - - - -Simpson [Page 11] - -RFC 1994 PPP CHAP August 1996 - - -References - - [1] Simpson, W., Editor, "The Point-to-Point Protocol (PPP)", STD - 51, RFC 1661, DayDreamer, July 1994. - - [2] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC - 1700, USC/Information Sciences Institute, October 1994. - - [3] Rivest, R., and S. Dusse, "The MD5 Message-Digest Algorithm", - MIT Laboratory for Computer Science and RSA Data Security, - Inc., RFC 1321, April 1992. - - - -Contacts - - Comments should be submitted to the ietf-ppp@merit.edu mailing list. - - This document was reviewed by the Point-to-Point Protocol Working - Group of the Internet Engineering Task Force (IETF). The working - group can be contacted via the current chair: - - Karl Fox - Ascend Communications - 3518 Riverside Drive, Suite 101 - Columbus, Ohio 43221 - - karl@MorningStar.com - karl@Ascend.com - - - Questions about this memo can also be directed to: - - William Allen Simpson - DayDreamer - Computer Systems Consulting Services - 1384 Fontaine - Madison Heights, Michigan 48071 - - wsimpson@UMich.edu - wsimpson@GreenDragon.com (preferred) - - - - - - - - - - -Simpson [Page 12] - - diff --git a/ext/picotcp/RFC/rfc2012.txt b/ext/picotcp/RFC/rfc2012.txt deleted file mode 100644 index b5aee40..0000000 --- a/ext/picotcp/RFC/rfc2012.txt +++ /dev/null @@ -1,563 +0,0 @@ - - - - - - -Network Working Group K. McCloghrie, Editor -Request for Comments: 2012 Cisco Systems -Updates: 1213 November 1996 -Category: Standards Track - - - SNMPv2 Management Information Base - for the Transmission Control Protocol using SMIv2 - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -IESG Note: - - The IP, UDP, and TCP MIB modules currently support only IPv4. These - three modules use the IpAddress type defined as an OCTET STRING of - length 4 to represent the IPv4 32-bit internet addresses. (See RFC - 1902, SMI for SNMPv2.) They do not support the new 128-bit IPv6 - internet addresses. - -Table of Contents - - 1. Introduction ................................................ 1 - 2. Definitions ................................................. 2 - 2.1 The TCP Group .............................................. 3 - 2.2 Conformance Information .................................... 8 - 2.2.1 Compliance Statements .................................... 8 - 2.2.2 Units of Conformance ..................................... 9 - 3. Acknowledgements ............................................ 10 - 4. References .................................................. 10 - 5. Security Considerations ..................................... 10 - 6. Editor's Address ............................................ 10 - -1. Introduction - - A management system contains: several (potentially many) nodes, each - with a processing entity, termed an agent, which has access to - management instrumentation; at least one management station; and, a - management protocol, used to convey management information between - the agents and management stations. Operations of the protocol are - carried out under an administrative framework which defines - authentication, authorization, access control, and privacy policies. - - - - -McCloghrie Standards Track [Page 1] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - Management stations execute management applications which monitor and - control managed elements. Managed elements are devices such as - hosts, routers, terminal servers, etc., which are monitored and - controlled via access to their management information. - - Management information is viewed as a collection of managed objects, - residing in a virtual information store, termed the Management - Information Base (MIB). Collections of related objects are defined - in MIB modules. These modules are written using a subset of OSI's - Abstract Syntax Notation One (ASN.1) [1], termed the Structure of - Management Information (SMI) [2]. - - This document is the MIB module which defines managed objects for - managing implementations of the Transmission Control Protocol (TCP) - [3]. - - The managed objects in this MIB module were originally defined using - the SNMPv1 framework as a part of MIB-II [4]. This document defines - the same objects for TCP using the SNMPv2 framework. - -2. Definitions - -TCP-MIB DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-IDENTITY, OBJECT-TYPE, Integer32, Gauge32, - Counter32, IpAddress, mib-2 FROM SNMPv2-SMI - MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF; - -tcpMIB MODULE-IDENTITY - LAST-UPDATED "9411010000Z" - ORGANIZATION "IETF SNMPv2 Working Group" - CONTACT-INFO - " Keith McCloghrie - - Postal: Cisco Systems, Inc. - 170 West Tasman Drive - San Jose, CA 95134-1706 - US - - Phone: +1 408 526 5260 - Email: kzm@cisco.com" - - - - - - - - - -McCloghrie Standards Track [Page 2] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - DESCRIPTION - "The MIB module for managing TCP implementations." - REVISION "9103310000Z" - DESCRIPTION - "The initial revision of this MIB module was part of MIB- - II." - ::= { mib-2 49 } - --- the TCP group - -tcp OBJECT IDENTIFIER ::= { mib-2 6 } - -tcpRtoAlgorithm OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - constant(2), -- a constant rto - rsre(3), -- MIL-STD-1778, Appendix B - vanj(4) -- Van Jacobson's algorithm [5] - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The algorithm used to determine the timeout value used for - retransmitting unacknowledged octets." - ::= { tcp 1 } - -tcpRtoMin OBJECT-TYPE - SYNTAX Integer32 - UNITS "milliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The minimum value permitted by a TCP implementation for the - retransmission timeout, measured in milliseconds. More - refined semantics for objects of this type depend upon the - algorithm used to determine the retransmission timeout. In - particular, when the timeout algorithm is rsre(3), an object - of this type has the semantics of the LBOUND quantity - described in RFC 793." - ::= { tcp 2 } - -tcpRtoMax OBJECT-TYPE - SYNTAX Integer32 - UNITS "milliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The maximum value permitted by a TCP implementation for the - - - -McCloghrie Standards Track [Page 3] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - retransmission timeout, measured in milliseconds. More - refined semantics for objects of this type depend upon the - algorithm used to determine the retransmission timeout. In - particular, when the timeout algorithm is rsre(3), an object - of this type has the semantics of the UBOUND quantity - described in RFC 793." - ::= { tcp 3 } - -tcpMaxConn OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The limit on the total number of TCP connections the entity - can support. In entities where the maximum number of - connections is dynamic, this object should contain the value - -1." - ::= { tcp 4 } - -tcpActiveOpens OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times TCP connections have made a direct - transition to the SYN-SENT state from the CLOSED state." - ::= { tcp 5 } - -tcpPassiveOpens OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times TCP connections have made a direct - transition to the SYN-RCVD state from the LISTEN state." - ::= { tcp 6 } - -tcpAttemptFails OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times TCP connections have made a direct - transition to the CLOSED state from either the SYN-SENT - state or the SYN-RCVD state, plus the number of times TCP - connections have made a direct transition to the LISTEN - state from the SYN-RCVD state." - ::= { tcp 7 } - - - -McCloghrie Standards Track [Page 4] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - -tcpEstabResets OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times TCP connections have made a direct - transition to the CLOSED state from either the ESTABLISHED - state or the CLOSE-WAIT state." - ::= { tcp 8 } - -tcpCurrEstab OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of TCP connections for which the current state - is either ESTABLISHED or CLOSE- WAIT." - ::= { tcp 9 } - - -tcpInSegs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments received, including those - received in error. This count includes segments received on - currently established connections." - ::= { tcp 10 } - -tcpOutSegs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments sent, including those on - current connections but excluding those containing only - retransmitted octets." - ::= { tcp 11 } - -tcpRetransSegs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments retransmitted - that is, the - number of TCP segments transmitted containing one or more - previously transmitted octets." - - - -McCloghrie Standards Track [Page 5] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - ::= { tcp 12 } - - --- the TCP Connection table - --- The TCP connection table contains information about this --- entity's existing TCP connections. - -tcpConnTable OBJECT-TYPE - SYNTAX SEQUENCE OF TcpConnEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table containing TCP connection-specific information." - ::= { tcp 13 } - -tcpConnEntry OBJECT-TYPE - SYNTAX TcpConnEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A conceptual row of the tcpConnTable containing information - about a particular current TCP connection. Each row of this - table is transient, in that it ceases to exist when (or soon - after) the connection makes the transition to the CLOSED - state." - INDEX { tcpConnLocalAddress, - tcpConnLocalPort, - tcpConnRemAddress, - tcpConnRemPort } - ::= { tcpConnTable 1 } - -TcpConnEntry ::= SEQUENCE { - tcpConnState INTEGER, - tcpConnLocalAddress IpAddress, - tcpConnLocalPort INTEGER, - tcpConnRemAddress IpAddress, - tcpConnRemPort INTEGER - } - -tcpConnState OBJECT-TYPE - SYNTAX INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - - - -McCloghrie Standards Track [Page 6] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11), - deleteTCB(12) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The state of this TCP connection. - - The only value which may be set by a management station is - deleteTCB(12). Accordingly, it is appropriate for an agent - to return a `badValue' response if a management station - attempts to set this object to any other value. - - If a management station sets this object to the value - deleteTCB(12), then this has the effect of deleting the TCB - (as defined in RFC 793) of the corresponding connection on - the managed node, resulting in immediate termination of the - connection. - - As an implementation-specific option, a RST segment may be - sent from the managed node to the other TCP endpoint (note - however that RST segments are not sent reliably)." - ::= { tcpConnEntry 1 } - -tcpConnLocalAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The local IP address for this TCP connection. In the case - of a connection in the listen state which is willing to - accept connections for any IP interface associated with the - node, the value 0.0.0.0 is used." - ::= { tcpConnEntry 2 } - -tcpConnLocalPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The local port number for this TCP connection." - ::= { tcpConnEntry 3 } - -tcpConnRemAddress OBJECT-TYPE - - - -McCloghrie Standards Track [Page 7] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The remote IP address for this TCP connection." - ::= { tcpConnEntry 4 } - -tcpConnRemPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The remote port number for this TCP connection." - ::= { tcpConnEntry 5 } - -tcpInErrs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments received in error (e.g., bad - TCP checksums)." - ::= { tcp 14 } - -tcpOutRsts OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of TCP segments sent containing the RST flag." - ::= { tcp 15 } - --- conformance information - -tcpMIBConformance OBJECT IDENTIFIER ::= { tcpMIB 2 } - -tcpMIBCompliances OBJECT IDENTIFIER ::= { tcpMIBConformance 1 } -tcpMIBGroups OBJECT IDENTIFIER ::= { tcpMIBConformance 2 } - - --- compliance statements - -tcpMIBCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for SNMPv2 entities which - implement TCP." - MODULE -- this module - - - -McCloghrie Standards Track [Page 8] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - - MANDATORY-GROUPS { tcpGroup - } - ::= { tcpMIBCompliances 1 } - --- units of conformance - -tcpGroup OBJECT-GROUP - OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, - tcpMaxConn, tcpActiveOpens, - tcpPassiveOpens, tcpAttemptFails, - tcpEstabResets, tcpCurrEstab, tcpInSegs, - tcpOutSegs, tcpRetransSegs, tcpConnState, - tcpConnLocalAddress, tcpConnLocalPort, - tcpConnRemAddress, tcpConnRemPort, - tcpInErrs, tcpOutRsts } - STATUS current - DESCRIPTION - "The tcp group of objects providing for management of TCP - entities." - ::= { tcpMIBGroups 1 } - -END - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -McCloghrie Standards Track [Page 9] - -RFC 2012 SNMPv2 MIB for TCP November 1996 - - -3. Acknowledgements - - This document contains a modified subset of RFC 1213. - -4. References - - [1] Information processing systems - Open Systems Interconnection - - Specification of Abstract Syntax Notation One (ASN.1), - International Organization for Standardization. International - Standard 8824, (December, 1987). - - [2] McCloghrie, K., Editor, "Structure of Management Information - for version 2 of the Simple Network Management Protocol - (SNMPv2)", RFC 1902, Cisco Systems, January 1996. - - [3] Postel, J., "Transmission Control Protocol - DARPA Internet - Program Protocol Specification", STD 7, RFC 793, DARPA, - September 1981. - - [4] McCloghrie, K., and M. Rose, "Management Information Base for - Network Management of TCP/IP-based internets: MIB-II", STD 17, - RFC 1213, March 1991. - - [5] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM 1988, - Stanford, California. - -5. Security Considerations - - Security issues are not discussed in this memo. - -6. Editor's Address - - Keith McCloghrie - Cisco Systems, Inc. - 170 West Tasman Drive - San Jose, CA 95134-1706 - US - - Phone: +1 408 526 5260 - EMail: kzm@cisco.com - - - - - - - - - - - -McCloghrie Standards Track [Page 10] - diff --git a/ext/picotcp/RFC/rfc2018.txt b/ext/picotcp/RFC/rfc2018.txt deleted file mode 100644 index 1d84811..0000000 --- a/ext/picotcp/RFC/rfc2018.txt +++ /dev/null @@ -1,675 +0,0 @@ - - - - - - -Network Working Group M. Mathis -Request for Comments: 2018 J. Mahdavi -Category: Standards Track PSC - S. Floyd - LBNL - A. Romanow - Sun Microsystems - October 1996 - - - TCP Selective Acknowledgment Options - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Abstract - - TCP may experience poor performance when multiple packets are lost - from one window of data. With the limited information available - from cumulative acknowledgments, a TCP sender can only learn about a - single lost packet per round trip time. An aggressive sender could - choose to retransmit packets early, but such retransmitted segments - may have already been successfully received. - - A Selective Acknowledgment (SACK) mechanism, combined with a - selective repeat retransmission policy, can help to overcome these - limitations. The receiving TCP sends back SACK packets to the sender - informing the sender of data that has been received. The sender can - then retransmit only the missing data segments. - - This memo proposes an implementation of SACK and discusses its - performance and related issues. - -Acknowledgements - - Much of the text in this document is taken directly from RFC1072 "TCP - Extensions for Long-Delay Paths" by Bob Braden and Van Jacobson. The - authors would like to thank Kevin Fall (LBNL), Christian Huitema - (INRIA), Van Jacobson (LBNL), Greg Miller (MITRE), Greg Minshall - (Ipsilon), Lixia Zhang (XEROX PARC and UCLA), Dave Borman (BSDI), - Allison Mankin (ISI) and others for their review and constructive - comments. - - - - -Mathis, et. al. Standards Track [Page 1] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - -1. Introduction - - Multiple packet losses from a window of data can have a catastrophic - effect on TCP throughput. TCP [Postel81] uses a cumulative - acknowledgment scheme in which received segments that are not at the - left edge of the receive window are not acknowledged. This forces - the sender to either wait a roundtrip time to find out about each - lost packet, or to unnecessarily retransmit segments which have been - correctly received [Fall95]. With the cumulative acknowledgment - scheme, multiple dropped segments generally cause TCP to lose its - ACK-based clock, reducing overall throughput. - - Selective Acknowledgment (SACK) is a strategy which corrects this - behavior in the face of multiple dropped segments. With selective - acknowledgments, the data receiver can inform the sender about all - segments that have arrived successfully, so the sender need - retransmit only the segments that have actually been lost. - - Several transport protocols, including NETBLT [Clark87], XTP - [Strayer92], RDP [Velten84], NADIR [Huitema81], and VMTP [Cheriton88] - have used selective acknowledgment. There is some empirical evidence - in favor of selective acknowledgments -- simple experiments with RDP - have shown that disabling the selective acknowledgment facility - greatly increases the number of retransmitted segments over a lossy, - high-delay Internet path [Partridge87]. A recent simulation study by - Kevin Fall and Sally Floyd [Fall95], demonstrates the strength of TCP - with SACK over the non-SACK Tahoe and Reno TCP implementations. - - RFC1072 [VJ88] describes one possible implementation of SACK options - for TCP. Unfortunately, it has never been deployed in the Internet, - as there was disagreement about how SACK options should be used in - conjunction with the TCP window shift option (initially described - RFC1072 and revised in [Jacobson92]). - - We propose slight modifications to the SACK options as proposed in - RFC1072. Specifically, sending a selective acknowledgment for the - most recently received data reduces the need for long SACK options - [Keshav94, Mathis95]. In addition, the SACK option now carries full - 32 bit sequence numbers. These two modifications represent the only - changes to the proposal in RFC1072. They make SACK easier to - implement and address concerns about robustness. - - The selective acknowledgment extension uses two TCP options. The - first is an enabling option, "SACK-permitted", which may be sent in a - SYN segment to indicate that the SACK option can be used once the - connection is established. The other is the SACK option itself, - which may be sent over an established connection once permission has - been given by SACK-permitted. - - - -Mathis, et. al. Standards Track [Page 2] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - The SACK option is to be included in a segment sent from a TCP that - is receiving data to the TCP that is sending that data; we will refer - to these TCP's as the data receiver and the data sender, - respectively. We will consider a particular simplex data flow; any - data flowing in the reverse direction over the same connection can be - treated independently. - -2. Sack-Permitted Option - - This two-byte option may be sent in a SYN by a TCP that has been - extended to receive (and presumably process) the SACK option once the - connection has opened. It MUST NOT be sent on non-SYN segments. - - TCP Sack-Permitted Option: - - Kind: 4 - - +---------+---------+ - | Kind=4 | Length=2| - +---------+---------+ - -3. Sack Option Format - - The SACK option is to be used to convey extended acknowledgment - information from the receiver to the sender over an established TCP - connection. - - TCP SACK Option: - - Kind: 5 - - Length: Variable - - +--------+--------+ - | Kind=5 | Length | - +--------+--------+--------+--------+ - | Left Edge of 1st Block | - +--------+--------+--------+--------+ - | Right Edge of 1st Block | - +--------+--------+--------+--------+ - | | - / . . . / - | | - +--------+--------+--------+--------+ - | Left Edge of nth Block | - +--------+--------+--------+--------+ - | Right Edge of nth Block | - +--------+--------+--------+--------+ - - - -Mathis, et. al. Standards Track [Page 3] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - The SACK option is to be sent by a data receiver to inform the data - sender of non-contiguous blocks of data that have been received and - queued. The data receiver awaits the receipt of data (perhaps by - means of retransmissions) to fill the gaps in sequence space between - received blocks. When missing segments are received, the data - receiver acknowledges the data normally by advancing the left window - edge in the Acknowledgement Number Field of the TCP header. The SACK - option does not change the meaning of the Acknowledgement Number - field. - - This option contains a list of some of the blocks of contiguous - sequence space occupied by data that has been received and queued - within the window. - - Each contiguous block of data queued at the data receiver is defined - in the SACK option by two 32-bit unsigned integers in network byte - order: - - * Left Edge of Block - - This is the first sequence number of this block. - - * Right Edge of Block - - This is the sequence number immediately following the last - sequence number of this block. - - Each block represents received bytes of data that are contiguous and - isolated; that is, the bytes just below the block, (Left Edge of - Block - 1), and just above the block, (Right Edge of Block), have not - been received. - - A SACK option that specifies n blocks will have a length of 8*n+2 - bytes, so the 40 bytes available for TCP options can specify a - maximum of 4 blocks. It is expected that SACK will often be used in - conjunction with the Timestamp option used for RTTM [Jacobson92], - which takes an additional 10 bytes (plus two bytes of padding); thus - a maximum of 3 SACK blocks will be allowed in this case. - - The SACK option is advisory, in that, while it notifies the data - sender that the data receiver has received the indicated segments, - the data receiver is permitted to later discard data which have been - reported in a SACK option. A discussion appears below in Section 8 - of the consequences of advisory SACK, in particular that the data - receiver may renege, or drop already SACKed data. - - - - - - -Mathis, et. al. Standards Track [Page 4] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - -4. Generating Sack Options: Data Receiver Behavior - - If the data receiver has received a SACK-Permitted option on the SYN - for this connection, the data receiver MAY elect to generate SACK - options as described below. If the data receiver generates SACK - options under any circumstance, it SHOULD generate them under all - permitted circumstances. If the data receiver has not received a - SACK-Permitted option for a given connection, it MUST NOT send SACK - options on that connection. - - If sent at all, SACK options SHOULD be included in all ACKs which do - not ACK the highest sequence number in the data receiver's queue. In - this situation the network has lost or mis-ordered data, such that - the receiver holds non-contiguous data in its queue. RFC 1122, - Section 4.2.2.21, discusses the reasons for the receiver to send ACKs - in response to additional segments received in this state. The - receiver SHOULD send an ACK for every valid segment that arrives - containing new data, and each of these "duplicate" ACKs SHOULD bear a - SACK option. - - If the data receiver chooses to send a SACK option, the following - rules apply: - - * The first SACK block (i.e., the one immediately following the - kind and length fields in the option) MUST specify the contiguous - block of data containing the segment which triggered this ACK, - unless that segment advanced the Acknowledgment Number field in - the header. This assures that the ACK with the SACK option - reflects the most recent change in the data receiver's buffer - queue. - - * The data receiver SHOULD include as many distinct SACK blocks as - possible in the SACK option. Note that the maximum available - option space may not be sufficient to report all blocks present in - the receiver's queue. - - * The SACK option SHOULD be filled out by repeating the most - recently reported SACK blocks (based on first SACK blocks in - previous SACK options) that are not subsets of a SACK block - already included in the SACK option being constructed. This - assures that in normal operation, any segment remaining part of a - non-contiguous block of data held by the data receiver is reported - in at least three successive SACK options, even for large-window - TCP implementations [RFC1323]). After the first SACK block, the - following SACK blocks in the SACK option may be listed in - arbitrary order. - - - - - -Mathis, et. al. Standards Track [Page 5] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - It is very important that the SACK option always reports the block - containing the most recently received segment, because this provides - the sender with the most up-to-date information about the state of - the network and the data receiver's queue. - -5. Interpreting the Sack Option and Retransmission Strategy: Data - Sender Behavior - - When receiving an ACK containing a SACK option, the data sender - SHOULD record the selective acknowledgment for future reference. The - data sender is assumed to have a retransmission queue that contains - the segments that have been transmitted but not yet acknowledged, in - sequence-number order. If the data sender performs re-packetization - before retransmission, the block boundaries in a SACK option that it - receives may not fall on boundaries of segments in the retransmission - queue; however, this does not pose a serious difficulty for the - sender. - - One possible implementation of the sender's behavior is as follows. - Let us suppose that for each segment in the retransmission queue - there is a (new) flag bit "SACKed", to be used to indicate that this - particular segment has been reported in a SACK option. - - When an acknowledgment segment arrives containing a SACK option, the - data sender will turn on the SACKed bits for segments that have been - selectively acknowledged. More specifically, for each block in the - SACK option, the data sender will turn on the SACKed flags for all - segments in the retransmission queue that are wholly contained within - that block. This requires straightforward sequence number - comparisons. - - After the SACKed bit is turned on (as the result of processing a - received SACK option), the data sender will skip that segment during - any later retransmission. Any segment that has the SACKed bit turned - off and is less than the highest SACKed segment is available for - retransmission. - - After a retransmit timeout the data sender SHOULD turn off all of the - SACKed bits, since the timeout might indicate that the data receiver - has reneged. The data sender MUST retransmit the segment at the left - edge of the window after a retransmit timeout, whether or not the - SACKed bit is on for that segment. A segment will not be dequeued - and its buffer freed until the left window edge is advanced over it. - - - - - - - - -Mathis, et. al. Standards Track [Page 6] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - -5.1 Congestion Control Issues - - This document does not attempt to specify in detail the congestion - control algorithms for implementations of TCP with SACK. However, - the congestion control algorithms present in the de facto standard - TCP implementations MUST be preserved [Stevens94]. In particular, to - preserve robustness in the presence of packets reordered by the - network, recovery is not triggered by a single ACK reporting out-of- - order packets at the receiver. Further, during recovery the data - sender limits the number of segments sent in response to each ACK. - Existing implementations limit the data sender to sending one segment - during Reno-style fast recovery, or to two segments during slow-start - [Jacobson88]. Other aspects of congestion control, such as reducing - the congestion window in response to congestion, must similarly be - preserved. - - The use of time-outs as a fall-back mechanism for detecting dropped - packets is unchanged by the SACK option. Because the data receiver - is allowed to discard SACKed data, when a retransmit timeout occurs - the data sender MUST ignore prior SACK information in determining - which data to retransmit. - - Future research into congestion control algorithms may take advantage - of the additional information provided by SACK. One such area for - future research concerns modifications to TCP for a wireless or - satellite environment where packet loss is not necessarily an - indication of congestion. - -6. Efficiency and Worst Case Behavior - - If the return path carrying ACKs and SACK options were lossless, one - block per SACK option packet would always be sufficient. Every - segment arriving while the data receiver holds discontinuous data - would cause the data receiver to send an ACK with a SACK option - containing the one altered block in the receiver's queue. The data - sender is thus able to construct a precise replica of the receiver's - queue by taking the union of all the first SACK blocks. - - - - - - - - - - - - - - -Mathis, et. al. Standards Track [Page 7] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - Since the return path is not lossless, the SACK option is defined to - include more than one SACK block in a single packet. The redundant - blocks in the SACK option packet increase the robustness of SACK - delivery in the presence of lost ACKs. For a receiver that is also - using the time stamp option [Jacobson92], the SACK option has room to - include three SACK blocks. Thus each SACK block will generally be - repeated at least three times, if necessary, once in each of three - successive ACK packets. However, if all of the ACK packets reporting - a particular SACK block are dropped, then the sender might assume - that the data in that SACK block has not been received, and - unnecessarily retransmit those segments. - - The deployment of other TCP options may reduce the number of - available SACK blocks to 2 or even to 1. This will reduce the - redundancy of SACK delivery in the presence of lost ACKs. Even so, - the exposure of TCP SACK in regard to the unnecessary retransmission - of packets is strictly less than the exposure of current - implementations of TCP. The worst-case conditions necessary for the - sender to needlessly retransmit data is discussed in more detail in a - separate document [Floyd96]. - - Older TCP implementations which do not have the SACK option will not - be unfairly disadvantaged when competing against SACK-capable TCPs. - This issue is discussed in more detail in [Floyd96]. - -7. Sack Option Examples - - The following examples attempt to demonstrate the proper behavior of - SACK generation by the data receiver. - - Assume the left window edge is 5000 and that the data transmitter - sends a burst of 8 segments, each containing 500 data bytes. - - Case 1: The first 4 segments are received but the last 4 are - dropped. - - The data receiver will return a normal TCP ACK segment - acknowledging sequence number 7000, with no SACK option. - - - - - - - - - - - - - -Mathis, et. al. Standards Track [Page 8] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - Case 2: The first segment is dropped but the remaining 7 are - received. - - Upon receiving each of the last seven packets, the data - receiver will return a TCP ACK segment that acknowledges - sequence number 5000 and contains a SACK option specifying - one block of queued data: - - Triggering ACK Left Edge Right Edge - Segment - - 5000 (lost) - 5500 5000 5500 6000 - 6000 5000 5500 6500 - 6500 5000 5500 7000 - 7000 5000 5500 7500 - 7500 5000 5500 8000 - 8000 5000 5500 8500 - 8500 5000 5500 9000 - - - Case 3: The 2nd, 4th, 6th, and 8th (last) segments are - dropped. - - The data receiver ACKs the first packet normally. The - third, fifth, and seventh packets trigger SACK options as - follows: - - Triggering ACK First Block 2nd Block 3rd Block - Segment Left Right Left Right Left Right - Edge Edge Edge Edge Edge Edge - - 5000 5500 - 5500 (lost) - 6000 5500 6000 6500 - 6500 (lost) - 7000 5500 7000 7500 6000 6500 - 7500 (lost) - 8000 5500 8000 8500 7000 7500 6000 6500 - 8500 (lost) - - - - - - - - - - - -Mathis, et. al. Standards Track [Page 9] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - Suppose at this point, the 4th packet is received out of order. - (This could either be because the data was badly misordered in the - network, or because the 2nd packet was retransmitted and lost, and - then the 4th packet was retransmitted). At this point the data - receiver has only two SACK blocks to report. The data receiver - replies with the following Selective Acknowledgment: - - Triggering ACK First Block 2nd Block 3rd Block - Segment Left Right Left Right Left Right - Edge Edge Edge Edge Edge Edge - - 6500 5500 6000 7500 8000 8500 - - Suppose at this point, the 2nd segment is received. The data - receiver then replies with the following Selective Acknowledgment: - - Triggering ACK First Block 2nd Block 3rd Block - Segment Left Right Left Right Left Right - Edge Edge Edge Edge Edge Edge - - 5500 7500 8000 8500 - -8. Data Receiver Reneging - - Note that the data receiver is permitted to discard data in its queue - that has not been acknowledged to the data sender, even if the data - has already been reported in a SACK option. Such discarding of - SACKed packets is discouraged, but may be used if the receiver runs - out of buffer space. - - The data receiver MAY elect not to keep data which it has reported in - a SACK option. In this case, the receiver SACK generation is - additionally qualified: - - * The first SACK block MUST reflect the newest segment. Even if - the newest segment is going to be discarded and the receiver has - already discarded adjacent segments, the first SACK block MUST - report, at a minimum, the left and right edges of the newest - segment. - - * Except for the newest segment, all SACK blocks MUST NOT report - any old data which is no longer actually held by the receiver. - - Since the data receiver may later discard data reported in a SACK - option, the sender MUST NOT discard data before it is acknowledged by - the Acknowledgment Number field in the TCP header. - - - - - -Mathis, et. al. Standards Track [Page 10] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - -9. Security Considerations - - This document neither strengthens nor weakens TCP's current security - properties. - -10. References - - [Cheriton88] Cheriton, D., "VMTP: Versatile Message Transaction - Protocol", RFC 1045, Stanford University, February 1988. - - [Clark87] Clark, D., Lambert, M., and L. Zhang, "NETBLT: A Bulk Data - Transfer Protocol", RFC 998, MIT, March 1987. - - [Fall95] Fall, K. and Floyd, S., "Comparisons of Tahoe, Reno, and - Sack TCP", ftp://ftp.ee.lbl.gov/papers/sacks.ps.Z, December 1995. - - [Floyd96] Floyd, S., "Issues of TCP with SACK", - ftp://ftp.ee.lbl.gov/papers/issues_sa.ps.Z, January 1996. - - [Huitema81] Huitema, C., and Valet, I., An Experiment on High Speed - File Transfer using Satellite Links, 7th Data Communication - Symposium, Mexico, October 1981. - - [Jacobson88] Jacobson, V., "Congestion Avoidance and Control", - Proceedings of SIGCOMM '88, Stanford, CA., August 1988. - - [Jacobson88}, Jacobson, V. and R. Braden, "TCP Extensions for Long- - Delay Paths", RFC 1072, October 1988. - - [Jacobson92] Jacobson, V., Braden, R., and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [Keshav94] Keshav, presentation to the Internet End-to-End Research - Group, November 1994. - - [Mathis95] Mathis, M., and Mahdavi, J., TCP Forward Acknowledgment - Option, presentation to the Internet End-to-End Research Group, June - 1995. - - [Partridge87] Partridge, C., "Private Communication", February 1987. - - [Postel81] Postel, J., "Transmission Control Protocol - DARPA - Internet Program Protocol Specification", RFC 793, DARPA, September - 1981. - - [Stevens94] Stevens, W., TCP/IP Illustrated, Volume 1: The Protocols, - Addison-Wesley, 1994. - - - - -Mathis, et. al. Standards Track [Page 11] - -RFC 2018 TCP Selective Acknowledgement Options October 1996 - - - [Strayer92] Strayer, T., Dempsey, B., and Weaver, A., XTP -- the - xpress transfer protocol. Addison-Wesley Publishing Company, 1992. - - [Velten84] Velten, D., Hinden, R., and J. Sax, "Reliable Data - Protocol", RFC 908, BBN, July 1984. - -11. Authors' Addresses - - Matt Mathis and Jamshid Mahdavi - Pittsburgh Supercomputing Center - 4400 Fifth Ave - Pittsburgh, PA 15213 - mathis@psc.edu - mahdavi@psc.edu - - Sally Floyd - Lawrence Berkeley National Laboratory - One Cyclotron Road - Berkeley, CA 94720 - floyd@ee.lbl.gov - - Allyn Romanow - Sun Microsystems, Inc. - 2550 Garcia Ave., MPK17-202 - Mountain View, CA 94043 - allyn@eng.sun.com - - - - - - - - - - - - - - - - - - - - - - - - - -Mathis, et. al. Standards Track [Page 12] - diff --git a/ext/picotcp/RFC/rfc2132.txt b/ext/picotcp/RFC/rfc2132.txt deleted file mode 100644 index e9c4f4b..0000000 --- a/ext/picotcp/RFC/rfc2132.txt +++ /dev/null @@ -1,1907 +0,0 @@ - - - - - - -Network Working Group S. Alexander -Request for Comments: 2132 Silicon Graphics, Inc. -Obsoletes: 1533 R. Droms -Category: Standards Track Bucknell University - March 1997 - - DHCP Options and BOOTP Vendor Extensions - -Status of this memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Abstract - - The Dynamic Host Configuration Protocol (DHCP) [1] provides a - framework for passing configuration information to hosts on a TCP/IP - network. Configuration parameters and other control information are - carried in tagged data items that are stored in the 'options' field - of the DHCP message. The data items themselves are also called - "options." - - This document specifies the current set of DHCP options. Future - options will be specified in separate RFCs. The current list of - valid options is also available in ftp://ftp.isi.edu/in- - notes/iana/assignments [22]. - - All of the vendor information extensions defined in RFC 1497 [2] may - be used as DHCP options. The definitions given in RFC 1497 are - included in this document, which supersedes RFC 1497. All of the - DHCP options defined in this document, except for those specific to - DHCP as defined in section 9, may be used as BOOTP vendor information - extensions. - -Table of Contents - - 1. Introduction .............................................. 2 - 2. BOOTP Extension/DHCP Option Field Format .................. 4 - 3. RFC 1497 Vendor Extensions ................................ 5 - 4. IP Layer Parameters per Host .............................. 11 - 5. IP Layer Parameters per Interface ........................ 13 - 6. Link Layer Parameters per Interface ....................... 16 - 7. TCP Parameters ............................................ 17 - 8. Application and Service Parameters ........................ 18 - 9. DHCP Extensions ........................................... 25 - - - -Alexander & Droms Standards Track [Page 1] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - 10. Defining new extensions ................................... 31 - 11. Acknowledgements .......................................... 31 - 12. References ................................................ 32 - 13. Security Considerations ................................... 33 - 14. Authors' Addresses ........................................ 34 - -1. Introduction - - This document specifies options for use with both the Dynamic Host - Configuration Protocol and the Bootstrap Protocol. - - The full description of DHCP packet formats may be found in the DHCP - specification document [1], and the full description of BOOTP packet - formats may be found in the BOOTP specification document [3]. This - document defines the format of information in the last field of DHCP - packets ('options') and of BOOTP packets ('vend'). The remainder of - this section defines a generalized use of this area for giving - information useful to a wide class of machines, operating systems and - configurations. Sites with a single DHCP or BOOTP server that is - shared among heterogeneous clients may choose to define other, site- - specific formats for the use of the 'options' field. - - Section 2 of this memo describes the formats of DHCP options and - BOOTP vendor extensions. Section 3 describes options defined in - previous documents for use with BOOTP (all may also be used with - DHCP). Sections 4-8 define new options intended for use with both - DHCP and BOOTP. Section 9 defines options used only in DHCP. - - References further describing most of the options defined in sections - 2-6 can be found in section 12. The use of the options defined in - section 9 is described in the DHCP specification [1]. - - Information on registering new options is contained in section 10. - - This document updates the definition of DHCP/BOOTP options that - appears in RFC1533. The classing mechanism has been extended to - include vendor classes as described in section 8.4 and 9.13. The new - procedure for defining new DHCP/BOOTP options in described in section - 10. Several new options, including NIS+ domain and servers, Mobile - IP home agent, SMTP server, TFTP server and Bootfile server, have - been added. Text giving definitions used throughout the document has - been added in section 1.1. Text emphasizing the need for uniqueness - of client-identifiers has been added to section 9.14. - - - - - - - - -Alexander & Droms Standards Track [Page 2] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -1.1 Requirements - - Throughout this document, the words that are used to define the - significance of particular requirements are capitalized. These words - are: - - o "MUST" - - This word or the adjective "REQUIRED" means that the item is an - absolute requirement of this specification. - - o "MUST NOT" - - This phrase means that the item is an absolute prohibition of - this specification. - - o "SHOULD" - - This word or the adjective "RECOMMENDED" means that there may - exist valid reasons in particular circumstances to ignore this - item, but the full implications should be understood and the case - carefully weighed before choosing a different course. - - o "SHOULD NOT" - - This phrase means that there may exist valid reasons in - particular circumstances when the listed behavior is acceptable - or even useful, but the full implications should be understood - and the case carefully weighed before implementing any behavior - described with this label. - - o "MAY" - - This word or the adjective "OPTIONAL" means that this item is - truly optional. One vendor may choose to include the item - because a particular marketplace requires it or because it - enhances the product, for example; another vendor may omit the - same item. - -1.2 Terminology - - This document uses the following terms: - - o "DHCP client" - - A DHCP client or "client" is an Internet host using DHCP to - obtain configuration parameters such as a network address. - - - - -Alexander & Droms Standards Track [Page 3] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - o "DHCP server" - - A DHCP server of "server"is an Internet host that returns - configuration parameters to DHCP clients. - - o "binding" - - A binding is a collection of configuration parameters, including - at least an IP address, associated with or "bound to" a DHCP - client. Bindings are managed by DHCP servers. - -2. BOOTP Extension/DHCP Option Field Format - - - DHCP options have the same format as the BOOTP 'vendor extensions' - defined in RFC 1497 [2]. Options may be fixed length or variable - length. All options begin with a tag octet, which uniquely - identifies the option. Fixed-length options without data consist of - only a tag octet. Only options 0 and 255 are fixed length. All - other options are variable-length with a length octet following the - tag octet. The value of the length octet does not include the two - octets specifying the tag and length. The length octet is followed - by "length" octets of data. Options containing NVT ASCII data SHOULD - NOT include a trailing NULL; however, the receiver of such options - MUST be prepared to delete trailing nulls if they exist. The - receiver MUST NOT require that a trailing null be included in the - data. In the case of some variable-length options the length field - is a constant but must still be specified. - - Any options defined subsequent to this document MUST contain a length - octet even if the length is fixed or zero. - - All multi-octet quantities are in network byte-order. - - When used with BOOTP, the first four octets of the vendor information - field have been assigned to the "magic cookie" (as suggested in RFC - 951). This field identifies the mode in which the succeeding data is - to be interpreted. The value of the magic cookie is the 4 octet - dotted decimal 99.130.83.99 (or hexadecimal number 63.82.53.63) in - network byte order. - - All of the "vendor extensions" defined in RFC 1497 are also DHCP - options. - - Option codes 128 to 254 (decimal) are reserved for site-specific - options. - - - - - -Alexander & Droms Standards Track [Page 4] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Except for the options in section 9, all options may be used with - either DHCP or BOOTP. - - Many of these options have their default values specified in other - documents. In particular, RFC 1122 [4] specifies default values for - most IP and TCP configuration parameters. - - Many options supply one or more 32-bit IP address. Use of IP - addresses rather than fully-qualified Domain Names (FQDNs) may make - future renumbering of IP hosts more difficult. Use of these - addresses is discouraged at sites that may require renumbering. - -3. RFC 1497 Vendor Extensions - - This section lists the vendor extensions as defined in RFC 1497. - They are defined here for completeness. - -3.1. Pad Option - - The pad option can be used to cause subsequent fields to align on - word boundaries. - - The code for the pad option is 0, and its length is 1 octet. - - Code - +-----+ - | 0 | - +-----+ - -3.2. End Option - - The end option marks the end of valid information in the vendor - field. Subsequent octets should be filled with pad options. - - The code for the end option is 255, and its length is 1 octet. - - Code - +-----+ - | 255 | - +-----+ - -3.3. Subnet Mask - - The subnet mask option specifies the client's subnet mask as per RFC - 950 [5]. - - If both the subnet mask and the router option are specified in a DHCP - reply, the subnet mask option MUST be first. - - - -Alexander & Droms Standards Track [Page 5] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for the subnet mask option is 1, and its length is 4 octets. - - Code Len Subnet Mask - +-----+-----+-----+-----+-----+-----+ - | 1 | 4 | m1 | m2 | m3 | m4 | - +-----+-----+-----+-----+-----+-----+ - -3.4. Time Offset - - The time offset field specifies the offset of the client's subnet in - seconds from Coordinated Universal Time (UTC). The offset is - expressed as a two's complement 32-bit integer. A positive offset - indicates a location east of the zero meridian and a negative offset - indicates a location west of the zero meridian. - - The code for the time offset option is 2, and its length is 4 octets. - - Code Len Time Offset - +-----+-----+-----+-----+-----+-----+ - | 2 | 4 | n1 | n2 | n3 | n4 | - +-----+-----+-----+-----+-----+-----+ - -3.5. Router Option - - The router option specifies a list of IP addresses for routers on the - client's subnet. Routers SHOULD be listed in order of preference. - - The code for the router option is 3. The minimum length for the - router option is 4 octets, and the length MUST always be a multiple - of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 3 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.6. Time Server Option - - The time server option specifies a list of RFC 868 [6] time servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for the time server option is 4. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - - - - - -Alexander & Droms Standards Track [Page 6] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 4 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.7. Name Server Option - - The name server option specifies a list of IEN 116 [7] name servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for the name server option is 5. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 5 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.8. Domain Name Server Option - - The domain name server option specifies a list of Domain Name System - (STD 13, RFC 1035 [8]) name servers available to the client. Servers - SHOULD be listed in order of preference. - - The code for the domain name server option is 6. The minimum length - for this option is 4 octets, and the length MUST always be a multiple - of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.9. Log Server Option - - The log server option specifies a list of MIT-LCS UDP log servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for the log server option is 7. The minimum length for this - option is 4 octets, and the length MUST always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 7 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - - - -Alexander & Droms Standards Track [Page 7] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -3.10. Cookie Server Option - - The cookie server option specifies a list of RFC 865 [9] cookie - servers available to the client. Servers SHOULD be listed in order - of preference. - - The code for the log server option is 8. The minimum length for this - option is 4 octets, and the length MUST always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 8 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.11. LPR Server Option - - The LPR server option specifies a list of RFC 1179 [10] line printer - servers available to the client. Servers SHOULD be listed in order - of preference. - - The code for the LPR server option is 9. The minimum length for this - option is 4 octets, and the length MUST always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 9 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.12. Impress Server Option - - The Impress server option specifies a list of Imagen Impress servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for the Impress server option is 10. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 10 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.13. Resource Location Server Option - - This option specifies a list of RFC 887 [11] Resource Location - servers available to the client. Servers SHOULD be listed in order - of preference. - - - -Alexander & Droms Standards Track [Page 8] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for this option is 11. The minimum length for this option - is 4 octets, and the length MUST always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 11 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.14. Host Name Option - - This option specifies the name of the client. The name may or may - not be qualified with the local domain name (see section 3.17 for the - preferred way to retrieve the domain name). See RFC 1035 for - character set restrictions. - - The code for this option is 12, and its minimum length is 1. - - Code Len Host Name - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 12 | n | h1 | h2 | h3 | h4 | h5 | h6 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -3.15. Boot File Size Option - - This option specifies the length in 512-octet blocks of the default - boot image for the client. The file length is specified as an - unsigned 16-bit integer. - - The code for this option is 13, and its length is 2. - - Code Len File Size - +-----+-----+-----+-----+ - | 13 | 2 | l1 | l2 | - +-----+-----+-----+-----+ - -3.16. Merit Dump File - - This option specifies the path-name of a file to which the client's - core image should be dumped in the event the client crashes. The - path is formatted as a character string consisting of characters from - the NVT ASCII character set. - - The code for this option is 14. Its minimum length is 1. - - Code Len Dump File Pathname - +-----+-----+-----+-----+-----+-----+--- - | 14 | n | n1 | n2 | n3 | n4 | ... - +-----+-----+-----+-----+-----+-----+--- - - - -Alexander & Droms Standards Track [Page 9] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -3.17. Domain Name - - This option specifies the domain name that client should use when - resolving hostnames via the Domain Name System. - - The code for this option is 15. Its minimum length is 1. - - Code Len Domain Name - +-----+-----+-----+-----+-----+-----+-- - | 15 | n | d1 | d2 | d3 | d4 | ... - +-----+-----+-----+-----+-----+-----+-- - -3.18. Swap Server - - This specifies the IP address of the client's swap server. - - The code for this option is 16 and its length is 4. - - Code Len Swap Server Address - +-----+-----+-----+-----+-----+-----+ - | 16 | n | a1 | a2 | a3 | a4 | - +-----+-----+-----+-----+-----+-----+ - -3.19. Root Path - - This option specifies the path-name that contains the client's root - disk. The path is formatted as a character string consisting of - characters from the NVT ASCII character set. - - The code for this option is 17. Its minimum length is 1. - - Code Len Root Disk Pathname - +-----+-----+-----+-----+-----+-----+--- - | 17 | n | n1 | n2 | n3 | n4 | ... - +-----+-----+-----+-----+-----+-----+--- - -3.20. Extensions Path - - A string to specify a file, retrievable via TFTP, which contains - information which can be interpreted in the same way as the 64-octet - vendor-extension field within the BOOTP response, with the following - exceptions: - - - the length of the file is unconstrained; - - all references to Tag 18 (i.e., instances of the - BOOTP Extensions Path field) within the file are - ignored. - - - - -Alexander & Droms Standards Track [Page 10] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for this option is 18. Its minimum length is 1. - - Code Len Extensions Pathname - +-----+-----+-----+-----+-----+-----+--- - | 18 | n | n1 | n2 | n3 | n4 | ... - +-----+-----+-----+-----+-----+-----+--- - -4. IP Layer Parameters per Host - - This section details the options that affect the operation of the IP - layer on a per-host basis. - -4.1. IP Forwarding Enable/Disable Option - - This option specifies whether the client should configure its IP - layer for packet forwarding. A value of 0 means disable IP - forwarding, and a value of 1 means enable IP forwarding. - - The code for this option is 19, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 19 | 1 | 0/1 | - +-----+-----+-----+ - -4.2. Non-Local Source Routing Enable/Disable Option - - This option specifies whether the client should configure its IP - layer to allow forwarding of datagrams with non-local source routes - (see Section 3.3.5 of [4] for a discussion of this topic). A value - of 0 means disallow forwarding of such datagrams, and a value of 1 - means allow forwarding. - - The code for this option is 20, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 20 | 1 | 0/1 | - +-----+-----+-----+ - -4.3. Policy Filter Option - - This option specifies policy filters for non-local source routing. - The filters consist of a list of IP addresses and masks which specify - destination/mask pairs with which to filter incoming source routes. - - Any source routed datagram whose next-hop address does not match one - of the filters should be discarded by the client. - - - -Alexander & Droms Standards Track [Page 11] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - See [4] for further information. - - The code for this option is 21. The minimum length of this option is - 8, and the length MUST be a multiple of 8. - - Code Len Address 1 Mask 1 - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - | 21 | n | a1 | a2 | a3 | a4 | m1 | m2 | m3 | m4 | - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - Address 2 Mask 2 - +-----+-----+-----+-----+-----+-----+-----+-----+--- - | a1 | a2 | a3 | a4 | m1 | m2 | m3 | m4 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+--- - -4.4. Maximum Datagram Reassembly Size - - This option specifies the maximum size datagram that the client - should be prepared to reassemble. The size is specified as a 16-bit - unsigned integer. The minimum value legal value is 576. - - The code for this option is 22, and its length is 2. - - Code Len Size - +-----+-----+-----+-----+ - | 22 | 2 | s1 | s2 | - +-----+-----+-----+-----+ - -4.5. Default IP Time-to-live - - This option specifies the default time-to-live that the client should - use on outgoing datagrams. The TTL is specified as an octet with a - value between 1 and 255. - - The code for this option is 23, and its length is 1. - - Code Len TTL - +-----+-----+-----+ - | 23 | 1 | ttl | - +-----+-----+-----+ - -4.6. Path MTU Aging Timeout Option - - This option specifies the timeout (in seconds) to use when aging Path - MTU values discovered by the mechanism defined in RFC 1191 [12]. The - timeout is specified as a 32-bit unsigned integer. - - The code for this option is 24, and its length is 4. - - - - -Alexander & Droms Standards Track [Page 12] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Code Len Timeout - +-----+-----+-----+-----+-----+-----+ - | 24 | 4 | t1 | t2 | t3 | t4 | - +-----+-----+-----+-----+-----+-----+ - -4.7. Path MTU Plateau Table Option - - This option specifies a table of MTU sizes to use when performing - Path MTU Discovery as defined in RFC 1191. The table is formatted as - a list of 16-bit unsigned integers, ordered from smallest to largest. - The minimum MTU value cannot be smaller than 68. - - The code for this option is 25. Its minimum length is 2, and the - length MUST be a multiple of 2. - - Code Len Size 1 Size 2 - +-----+-----+-----+-----+-----+-----+--- - | 25 | n | s1 | s2 | s1 | s2 | ... - +-----+-----+-----+-----+-----+-----+--- - -5. IP Layer Parameters per Interface - - This section details the options that affect the operation of the IP - layer on a per-interface basis. It is expected that a client can - issue multiple requests, one per interface, in order to configure - interfaces with their specific parameters. - -5.1. Interface MTU Option - - This option specifies the MTU to use on this interface. The MTU is - specified as a 16-bit unsigned integer. The minimum legal value for - the MTU is 68. - - The code for this option is 26, and its length is 2. - - Code Len MTU - +-----+-----+-----+-----+ - | 26 | 2 | m1 | m2 | - +-----+-----+-----+-----+ - -5.2. All Subnets are Local Option - - This option specifies whether or not the client may assume that all - subnets of the IP network to which the client is connected use the - same MTU as the subnet of that network to which the client is - directly connected. A value of 1 indicates that all subnets share - the same MTU. A value of 0 means that the client should assume that - some subnets of the directly connected network may have smaller MTUs. - - - -Alexander & Droms Standards Track [Page 13] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for this option is 27, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 27 | 1 | 0/1 | - +-----+-----+-----+ - -5.3. Broadcast Address Option - - This option specifies the broadcast address in use on the client's - subnet. Legal values for broadcast addresses are specified in - section 3.2.1.3 of [4]. - - The code for this option is 28, and its length is 4. - - Code Len Broadcast Address - +-----+-----+-----+-----+-----+-----+ - | 28 | 4 | b1 | b2 | b3 | b4 | - +-----+-----+-----+-----+-----+-----+ - -5.4. Perform Mask Discovery Option - - This option specifies whether or not the client should perform subnet - mask discovery using ICMP. A value of 0 indicates that the client - should not perform mask discovery. A value of 1 means that the - client should perform mask discovery. - - The code for this option is 29, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 29 | 1 | 0/1 | - +-----+-----+-----+ - -5.5. Mask Supplier Option - - This option specifies whether or not the client should respond to - subnet mask requests using ICMP. A value of 0 indicates that the - client should not respond. A value of 1 means that the client should - respond. - - The code for this option is 30, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 30 | 1 | 0/1 | - +-----+-----+-----+ - - - - -Alexander & Droms Standards Track [Page 14] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -5.6. Perform Router Discovery Option - - This option specifies whether or not the client should solicit - routers using the Router Discovery mechanism defined in RFC 1256 - [13]. A value of 0 indicates that the client should not perform - router discovery. A value of 1 means that the client should perform - router discovery. - - The code for this option is 31, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 31 | 1 | 0/1 | - +-----+-----+-----+ - -5.7. Router Solicitation Address Option - - This option specifies the address to which the client should transmit - router solicitation requests. - - The code for this option is 32, and its length is 4. - - Code Len Address - +-----+-----+-----+-----+-----+-----+ - | 32 | 4 | a1 | a2 | a3 | a4 | - +-----+-----+-----+-----+-----+-----+ - -5.8. Static Route Option - - This option specifies a list of static routes that the client should - install in its routing cache. If multiple routes to the same - destination are specified, they are listed in descending order of - priority. - - The routes consist of a list of IP address pairs. The first address - is the destination address, and the second address is the router for - the destination. - - The default route (0.0.0.0) is an illegal destination for a static - route. See section 3.5 for information about the router option. - - The code for this option is 33. The minimum length of this option is - 8, and the length MUST be a multiple of 8. - - - - - - - - -Alexander & Droms Standards Track [Page 15] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Code Len Destination 1 Router 1 - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - | 33 | n | d1 | d2 | d3 | d4 | r1 | r2 | r3 | r4 | - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - Destination 2 Router 2 - +-----+-----+-----+-----+-----+-----+-----+-----+--- - | d1 | d2 | d3 | d4 | r1 | r2 | r3 | r4 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+--- - -6. Link Layer Parameters per Interface - - This section lists the options that affect the operation of the data - link layer on a per-interface basis. - -6.1. Trailer Encapsulation Option - - This option specifies whether or not the client should negotiate the - use of trailers (RFC 893 [14]) when using the ARP protocol. A value - of 0 indicates that the client should not attempt to use trailers. A - value of 1 means that the client should attempt to use trailers. - - The code for this option is 34, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 34 | 1 | 0/1 | - +-----+-----+-----+ - -6.2. ARP Cache Timeout Option - - This option specifies the timeout in seconds for ARP cache entries. - The time is specified as a 32-bit unsigned integer. - - The code for this option is 35, and its length is 4. - - Code Len Time - +-----+-----+-----+-----+-----+-----+ - | 35 | 4 | t1 | t2 | t3 | t4 | - +-----+-----+-----+-----+-----+-----+ - -6.3. Ethernet Encapsulation Option - - This option specifies whether or not the client should use Ethernet - Version 2 (RFC 894 [15]) or IEEE 802.3 (RFC 1042 [16]) encapsulation - if the interface is an Ethernet. A value of 0 indicates that the - client should use RFC 894 encapsulation. A value of 1 means that the - client should use RFC 1042 encapsulation. - - - - -Alexander & Droms Standards Track [Page 16] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for this option is 36, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 36 | 1 | 0/1 | - +-----+-----+-----+ - -7. TCP Parameters - - This section lists the options that affect the operation of the TCP - layer on a per-interface basis. - -7.1. TCP Default TTL Option - - This option specifies the default TTL that the client should use when - sending TCP segments. The value is represented as an 8-bit unsigned - integer. The minimum value is 1. - - The code for this option is 37, and its length is 1. - - Code Len TTL - +-----+-----+-----+ - | 37 | 1 | n | - +-----+-----+-----+ - -7.2. TCP Keepalive Interval Option - - This option specifies the interval (in seconds) that the client TCP - should wait before sending a keepalive message on a TCP connection. - The time is specified as a 32-bit unsigned integer. A value of zero - indicates that the client should not generate keepalive messages on - connections unless specifically requested by an application. - - The code for this option is 38, and its length is 4. - - Code Len Time - +-----+-----+-----+-----+-----+-----+ - | 38 | 4 | t1 | t2 | t3 | t4 | - +-----+-----+-----+-----+-----+-----+ - -7.3. TCP Keepalive Garbage Option - - This option specifies the whether or not the client should send TCP - keepalive messages with a octet of garbage for compatibility with - older implementations. A value of 0 indicates that a garbage octet - should not be sent. A value of 1 indicates that a garbage octet - should be sent. - - - - -Alexander & Droms Standards Track [Page 17] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for this option is 39, and its length is 1. - - Code Len Value - +-----+-----+-----+ - | 39 | 1 | 0/1 | - +-----+-----+-----+ - -8. Application and Service Parameters - - This section details some miscellaneous options used to configure - miscellaneous applications and services. - -8.1. Network Information Service Domain Option - - This option specifies the name of the client's NIS [17] domain. The - domain is formatted as a character string consisting of characters - from the NVT ASCII character set. - - The code for this option is 40. Its minimum length is 1. - - Code Len NIS Domain Name - +-----+-----+-----+-----+-----+-----+--- - | 40 | n | n1 | n2 | n3 | n4 | ... - +-----+-----+-----+-----+-----+-----+--- - -8.2. Network Information Servers Option - - This option specifies a list of IP addresses indicating NIS servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for this option is 41. Its minimum length is 4, and the - length MUST be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 41 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.3. Network Time Protocol Servers Option - - This option specifies a list of IP addresses indicating NTP [18] - servers available to the client. Servers SHOULD be listed in order - of preference. - - The code for this option is 42. Its minimum length is 4, and the - length MUST be a multiple of 4. - - - - -Alexander & Droms Standards Track [Page 18] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 42 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.4. Vendor Specific Information - - This option is used by clients and servers to exchange vendor- - specific information. The information is an opaque object of n - octets, presumably interpreted by vendor-specific code on the clients - and servers. The definition of this information is vendor specific. - The vendor is indicated in the vendor class identifier option. - Servers not equipped to interpret the vendor-specific information - sent by a client MUST ignore it (although it may be reported). - Clients which do not receive desired vendor-specific information - SHOULD make an attempt to operate without it, although they may do so - (and announce they are doing so) in a degraded mode. - - If a vendor potentially encodes more than one item of information in - this option, then the vendor SHOULD encode the option using - "Encapsulated vendor-specific options" as described below: - - The Encapsulated vendor-specific options field SHOULD be encoded as a - sequence of code/length/value fields of identical syntax to the DHCP - options field with the following exceptions: - - 1) There SHOULD NOT be a "magic cookie" field in the encapsulated - vendor-specific extensions field. - - 2) Codes other than 0 or 255 MAY be redefined by the vendor within - the encapsulated vendor-specific extensions field, but SHOULD - conform to the tag-length-value syntax defined in section 2. - - 3) Code 255 (END), if present, signifies the end of the - encapsulated vendor extensions, not the end of the vendor - extensions field. If no code 255 is present, then the end of - the enclosing vendor-specific information field is taken as the - end of the encapsulated vendor-specific extensions field. - - The code for this option is 43 and its minimum length is 1. - - Code Len Vendor-specific information - +-----+-----+-----+-----+--- - | 43 | n | i1 | i2 | ... - +-----+-----+-----+-----+--- - - - - - - -Alexander & Droms Standards Track [Page 19] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - When encapsulated vendor-specific extensions are used, the - information bytes 1-n have the following format: - - Code Len Data item Code Len Data item Code - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - | T1 | n | d1 | d2 | ... | T2 | n | D1 | D2 | ... | ... | - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - -8.5. NetBIOS over TCP/IP Name Server Option - - The NetBIOS name server (NBNS) option specifies a list of RFC - 1001/1002 [19] [20] NBNS name servers listed in order of preference. - - The code for this option is 44. The minimum length of the option is - 4 octets, and the length must always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- - | 44 | n | a1 | a2 | a3 | a4 | b1 | b2 | b3 | b4 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- - -8.6. NetBIOS over TCP/IP Datagram Distribution Server Option - - The NetBIOS datagram distribution server (NBDD) option specifies a - list of RFC 1001/1002 NBDD servers listed in order of preference. The - code for this option is 45. The minimum length of the option is 4 - octets, and the length must always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- - | 45 | n | a1 | a2 | a3 | a4 | b1 | b2 | b3 | b4 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- - -8.7. NetBIOS over TCP/IP Node Type Option - - The NetBIOS node type option allows NetBIOS over TCP/IP clients which - are configurable to be configured as described in RFC 1001/1002. The - value is specified as a single octet which identifies the client type - as follows: - - Value Node Type - ----- --------- - 0x1 B-node - 0x2 P-node - 0x4 M-node - 0x8 H-node - - - - - -Alexander & Droms Standards Track [Page 20] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - In the above chart, the notation '0x' indicates a number in base-16 - (hexadecimal). - - The code for this option is 46. The length of this option is always - 1. - - Code Len Node Type - +-----+-----+-----------+ - | 46 | 1 | see above | - +-----+-----+-----------+ - -8.8. NetBIOS over TCP/IP Scope Option - - The NetBIOS scope option specifies the NetBIOS over TCP/IP scope - parameter for the client as specified in RFC 1001/1002. See [19], - [20], and [8] for character-set restrictions. - - The code for this option is 47. The minimum length of this option is - 1. - - Code Len NetBIOS Scope - +-----+-----+-----+-----+-----+-----+---- - | 47 | n | s1 | s2 | s3 | s4 | ... - +-----+-----+-----+-----+-----+-----+---- - -8.9. X Window System Font Server Option - - This option specifies a list of X Window System [21] Font servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for this option is 48. The minimum length of this option is - 4 octets, and the length MUST be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+--- - | 48 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+--- - -8.10. X Window System Display Manager Option - - This option specifies a list of IP addresses of systems that are - running the X Window System Display Manager and are available to the - client. - - Addresses SHOULD be listed in order of preference. - - - - - -Alexander & Droms Standards Track [Page 21] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for the this option is 49. The minimum length of this option - is 4, and the length MUST be a multiple of 4. - - Code Len Address 1 Address 2 - - +-----+-----+-----+-----+-----+-----+-----+-----+--- - | 49 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+--- - -8.11. Network Information Service+ Domain Option - - This option specifies the name of the client's NIS+ [17] domain. The - domain is formatted as a character string consisting of characters - from the NVT ASCII character set. - - The code for this option is 64. Its minimum length is 1. - - Code Len NIS Client Domain Name - +-----+-----+-----+-----+-----+-----+--- - | 64 | n | n1 | n2 | n3 | n4 | ... - +-----+-----+-----+-----+-----+-----+--- - -8.12. Network Information Service+ Servers Option - - This option specifies a list of IP addresses indicating NIS+ servers - available to the client. Servers SHOULD be listed in order of - preference. - - The code for this option is 65. Its minimum length is 4, and the - length MUST be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 65 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.13. Mobile IP Home Agent option - - This option specifies a list of IP addresses indicating mobile IP - home agents available to the client. Agents SHOULD be listed in - order of preference. - - The code for this option is 68. Its minimum length is 0 (indicating - no home agents are available) and the length MUST be a multiple of 4. - It is expected that the usual length will be four octets, containing - a single home agent's address. - - - - - -Alexander & Droms Standards Track [Page 22] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Code Len Home Agent Addresses (zero or more) - +-----+-----+-----+-----+-----+-----+-- - | 68 | n | a1 | a2 | a3 | a4 | ... - +-----+-----+-----+-----+-----+-----+-- - -8.14. Simple Mail Transport Protocol (SMTP) Server Option - - The SMTP server option specifies a list of SMTP servers available to - the client. Servers SHOULD be listed in order of preference. - - The code for the SMTP server option is 69. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 69 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.15. Post Office Protocol (POP3) Server Option - - The POP3 server option specifies a list of POP3 available to the - client. Servers SHOULD be listed in order of preference. - - The code for the POP3 server option is 70. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 70 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.16. Network News Transport Protocol (NNTP) Server Option - - The NNTP server option specifies a list of NNTP available to the - client. Servers SHOULD be listed in order of preference. - - The code for the NNTP server option is 71. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 71 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - - - - - -Alexander & Droms Standards Track [Page 23] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -8.17. Default World Wide Web (WWW) Server Option - - The WWW server option specifies a list of WWW available to the - client. Servers SHOULD be listed in order of preference. - - The code for the WWW server option is 72. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 72 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.18. Default Finger Server Option - - The Finger server option specifies a list of Finger available to the - client. Servers SHOULD be listed in order of preference. - - The code for the Finger server option is 73. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 73 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.19. Default Internet Relay Chat (IRC) Server Option - - The IRC server option specifies a list of IRC available to the - client. Servers SHOULD be listed in order of preference. - - The code for the IRC server option is 74. The minimum length for - this option is 4 octets, and the length MUST always be a multiple of - 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 74 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.20. StreetTalk Server Option - - The StreetTalk server option specifies a list of StreetTalk servers - available to the client. Servers SHOULD be listed in order of - preference. - - - - -Alexander & Droms Standards Track [Page 24] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for the StreetTalk server option is 75. The minimum length - for this option is 4 octets, and the length MUST always be a multiple - of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 75 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -8.21. StreetTalk Directory Assistance (STDA) Server Option - - The StreetTalk Directory Assistance (STDA) server option specifies a - list of STDA servers available to the client. Servers SHOULD be - listed in order of preference. - - The code for the StreetTalk Directory Assistance server option is 76. - The minimum length for this option is 4 octets, and the length MUST - always be a multiple of 4. - - Code Len Address 1 Address 2 - +-----+-----+-----+-----+-----+-----+-----+-----+-- - | 76 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... - +-----+-----+-----+-----+-----+-----+-----+-----+-- - -9. DHCP Extensions - - This section details the options that are specific to DHCP. - -9.1. Requested IP Address - - This option is used in a client request (DHCPDISCOVER) to allow the - client to request that a particular IP address be assigned. - - The code for this option is 50, and its length is 4. - - Code Len Address - +-----+-----+-----+-----+-----+-----+ - | 50 | 4 | a1 | a2 | a3 | a4 | - +-----+-----+-----+-----+-----+-----+ - -9.2. IP Address Lease Time - - This option is used in a client request (DHCPDISCOVER or DHCPREQUEST) - to allow the client to request a lease time for the IP address. In a - server reply (DHCPOFFER), a DHCP server uses this option to specify - the lease time it is willing to offer. - - - - - -Alexander & Droms Standards Track [Page 25] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The time is in units of seconds, and is specified as a 32-bit - unsigned integer. - - The code for this option is 51, and its length is 4. - - Code Len Lease Time - +-----+-----+-----+-----+-----+-----+ - | 51 | 4 | t1 | t2 | t3 | t4 | - +-----+-----+-----+-----+-----+-----+ - -9.3. Option Overload - - This option is used to indicate that the DHCP 'sname' or 'file' - fields are being overloaded by using them to carry DHCP options. A - DHCP server inserts this option if the returned parameters will - exceed the usual space allotted for options. - - If this option is present, the client interprets the specified - additional fields after it concludes interpretation of the standard - option fields. - - The code for this option is 52, and its length is 1. Legal values - for this option are: - - Value Meaning - ----- -------- - 1 the 'file' field is used to hold options - 2 the 'sname' field is used to hold options - 3 both fields are used to hold options - - Code Len Value - +-----+-----+-----+ - | 52 | 1 |1/2/3| - +-----+-----+-----+ - -9.4 TFTP server name - - This option is used to identify a TFTP server when the 'sname' field - in the DHCP header has been used for DHCP options. - - The code for this option is 66, and its minimum length is 1. - - Code Len TFTP server - +-----+-----+-----+-----+-----+--- - | 66 | n | c1 | c2 | c3 | ... - +-----+-----+-----+-----+-----+--- - - - - - -Alexander & Droms Standards Track [Page 26] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -9.5 Bootfile name - - This option is used to identify a bootfile when the 'file' field in - the DHCP header has been used for DHCP options. - - The code for this option is 67, and its minimum length is 1. - - Code Len Bootfile name - +-----+-----+-----+-----+-----+--- - | 67 | n | c1 | c2 | c3 | ... - +-----+-----+-----+-----+-----+--- - -9.6. DHCP Message Type - - This option is used to convey the type of the DHCP message. The code - for this option is 53, and its length is 1. Legal values for this - option are: - - Value Message Type - ----- ------------ - 1 DHCPDISCOVER - 2 DHCPOFFER - 3 DHCPREQUEST - 4 DHCPDECLINE - 5 DHCPACK - 6 DHCPNAK - 7 DHCPRELEASE - 8 DHCPINFORM - - Code Len Type - +-----+-----+-----+ - | 53 | 1 | 1-9 | - +-----+-----+-----+ - -9.7. Server Identifier - - This option is used in DHCPOFFER and DHCPREQUEST messages, and may - optionally be included in the DHCPACK and DHCPNAK messages. DHCP - servers include this option in the DHCPOFFER in order to allow the - client to distinguish between lease offers. DHCP clients use the - contents of the 'server identifier' field as the destination address - for any DHCP messages unicast to the DHCP server. DHCP clients also - indicate which of several lease offers is being accepted by including - this option in a DHCPREQUEST message. - - The identifier is the IP address of the selected server. - - The code for this option is 54, and its length is 4. - - - -Alexander & Droms Standards Track [Page 27] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - Code Len Address - +-----+-----+-----+-----+-----+-----+ - | 54 | 4 | a1 | a2 | a3 | a4 | - +-----+-----+-----+-----+-----+-----+ - -9.8. Parameter Request List - - This option is used by a DHCP client to request values for specified - configuration parameters. The list of requested parameters is - specified as n octets, where each octet is a valid DHCP option code - as defined in this document. - - The client MAY list the options in order of preference. The DHCP - server is not required to return the options in the requested order, - but MUST try to insert the requested options in the order requested - by the client. - - The code for this option is 55. Its minimum length is 1. - - Code Len Option Codes - +-----+-----+-----+-----+--- - | 55 | n | c1 | c2 | ... - +-----+-----+-----+-----+--- - -9.9. Message - - This option is used by a DHCP server to provide an error message to a - DHCP client in a DHCPNAK message in the event of a failure. A client - may use this option in a DHCPDECLINE message to indicate the why the - client declined the offered parameters. The message consists of n - octets of NVT ASCII text, which the client may display on an - available output device. - - The code for this option is 56 and its minimum length is 1. - - Code Len Text - +-----+-----+-----+-----+--- - | 56 | n | c1 | c2 | ... - +-----+-----+-----+-----+--- - -9.10. Maximum DHCP Message Size - - This option specifies the maximum length DHCP message that it is - willing to accept. The length is specified as an unsigned 16-bit - integer. A client may use the maximum DHCP message size option in - DHCPDISCOVER or DHCPREQUEST messages, but should not use the option - in DHCPDECLINE messages. - - - - -Alexander & Droms Standards Track [Page 28] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The code for this option is 57, and its length is 2. The minimum - legal value is 576 octets. - - Code Len Length - +-----+-----+-----+-----+ - | 57 | 2 | l1 | l2 | - +-----+-----+-----+-----+ - -9.11. Renewal (T1) Time Value - - This option specifies the time interval from address assignment until - the client transitions to the RENEWING state. - - The value is in units of seconds, and is specified as a 32-bit - unsigned integer. - - The code for this option is 58, and its length is 4. - - Code Len T1 Interval - +-----+-----+-----+-----+-----+-----+ - | 58 | 4 | t1 | t2 | t3 | t4 | - +-----+-----+-----+-----+-----+-----+ - -9.12. Rebinding (T2) Time Value - - This option specifies the time interval from address assignment until - the client transitions to the REBINDING state. - - The value is in units of seconds, and is specified as a 32-bit - unsigned integer. - - The code for this option is 59, and its length is 4. - - Code Len T2 Interval - +-----+-----+-----+-----+-----+-----+ - | 59 | 4 | t1 | t2 | t3 | t4 | - +-----+-----+-----+-----+-----+-----+ - -9.13. Vendor class identifier - - This option is used by DHCP clients to optionally identify the vendor - type and configuration of a DHCP client. The information is a string - of n octets, interpreted by servers. Vendors may choose to define - specific vendor class identifiers to convey particular configuration - or other identification information about a client. For example, the - identifier may encode the client's hardware configuration. Servers - not equipped to interpret the class-specific information sent by a - client MUST ignore it (although it may be reported). Servers that - - - -Alexander & Droms Standards Track [Page 29] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - respond SHOULD only use option 43 to return the vendor-specific - information to the client. - - The code for this option is 60, and its minimum length is 1. - - Code Len Vendor class Identifier - +-----+-----+-----+-----+--- - | 60 | n | i1 | i2 | ... - +-----+-----+-----+-----+--- - -9.14. Client-identifier - - This option is used by DHCP clients to specify their unique - identifier. DHCP servers use this value to index their database of - address bindings. This value is expected to be unique for all - clients in an administrative domain. - - Identifiers SHOULD be treated as opaque objects by DHCP servers. - - The client identifier MAY consist of type-value pairs similar to the - 'htype'/'chaddr' fields defined in [3]. For instance, it MAY consist - of a hardware type and hardware address. In this case the type field - SHOULD be one of the ARP hardware types defined in STD2 [22]. A - hardware type of 0 (zero) should be used when the value field - contains an identifier other than a hardware address (e.g. a fully - qualified domain name). - - For correct identification of clients, each client's client- - identifier MUST be unique among the client-identifiers used on the - subnet to which the client is attached. Vendors and system - administrators are responsible for choosing client-identifiers that - meet this requirement for uniqueness. - - The code for this option is 61, and its minimum length is 2. - - Code Len Type Client-Identifier - +-----+-----+-----+-----+-----+--- - | 61 | n | t1 | i1 | i2 | ... - +-----+-----+-----+-----+-----+--- - - - - - - - - - - - - -Alexander & Droms Standards Track [Page 30] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -10. Defining new extensions - - The author of a new DHCP option will follow these steps to obtain - acceptance of the option as a part of the DHCP Internet Standard: - - 1. The author devises the new option. - 2. The author requests a number for the new option from IANA by - contacting: - Internet Assigned Numbers Authority (IANA) - USC/Information Sciences Institute - 4676 Admiralty Way - Marina del Rey, California 90292-6695 - - or by email as: iana@iana.org - - 3. The author documents the new option, using the newly obtained - option number, as an Internet Draft. - 4. The author submits the Internet Draft for review through the IETF - standards process as defined in "Internet Official Protocol - Standards" (STD 1). The new option will be submitted for eventual - acceptance as an Internet Standard. - 5. The new option progresses through the IETF standards process; the - new option will be reviewed by the Dynamic Host Configuration - Working Group (if that group still exists), or as an Internet - Draft not submitted by an IETF working group. - 6. If the new option fails to gain acceptance as an Internet - Standard, the assigned option number will be returned to IANA for - reassignment. - - This procedure for defining new extensions will ensure that: - - * allocation of new option numbers is coordinated from a single - authority, - * new options are reviewed for technical correctness and - appropriateness, and - * documentation for new options is complete and published. - -11. Acknowledgements - - The author thanks the many (and too numerous to mention!) members of - the DHC WG for their tireless and ongoing efforts in the development - of DHCP and this document. - - The efforts of J Allard, Mike Carney, Dave Lapp, Fred Lien and John - Mendonca in organizing DHCP interoperability testing sessions are - gratefully acknowledged. - - - - - -Alexander & Droms Standards Track [Page 31] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - The development of this document was supported in part by grants from - the Corporation for National Research Initiatives (CNRI), Bucknell - University and Sun Microsystems. - -12. References - - [1] Droms, R., "Dynamic Host Configuration Protocol", RFC 2131, - Bucknell University, March 1997. - - [2] Reynolds, J., "BOOTP Vendor Information Extensions", RFC 1497, - USC/Information Sciences Institute, August 1993. - - [3] Croft, W., and J. Gilmore, "Bootstrap Protocol", RFC 951, - Stanford University and Sun Microsystems, September 1985. - - [4] Braden, R., Editor, "Requirements for Internet Hosts - - Communication Layers", STD 3, RFC 1122, USC/Information Sciences - Institute, October 1989. - - [5] Mogul, J., and J. Postel, "Internet Standard Subnetting - Procedure", STD 5, RFC 950, USC/Information Sciences Institute, - August 1985. - - [6] Postel, J., and K. Harrenstien, "Time Protocol", STD 26, RFC - 868, USC/Information Sciences Institute, SRI, May 1983. - - [7] Postel, J., "Name Server", IEN 116, USC/Information Sciences - Institute, August 1979. - - [8] Mockapetris, P., "Domain Names - Implementation and - Specification", STD 13, RFC 1035, USC/Information Sciences - Institute, November 1987. - - [9] Postel, J., "Quote of the Day Protocol", STD 23, RFC 865, - USC/Information Sciences Institute, May 1983. - - [10] McLaughlin, L., "Line Printer Daemon Protocol", RFC 1179, The - Wollongong Group, August 1990. - - [11] Accetta, M., "Resource Location Protocol", RFC 887, CMU, - December 1983. - - [12] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191, - DECWRL, Stanford University, November 1990. - - [13] Deering, S., "ICMP Router Discovery Messages", RFC 1256, - Xerox PARC, September 1991. - - - - -Alexander & Droms Standards Track [Page 32] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - - [14] Leffler, S. and M. Karels, "Trailer Encapsulations", RFC 893, - U. C. Berkeley, April 1984. - - [15] Hornig, C., "Standard for the Transmission of IP Datagrams over - Ethernet Networks", RFC 894, Symbolics, April 1984. - - [16] Postel, J. and J. Reynolds, "Standard for the Transmission of - IP Datagrams Over IEEE 802 Networks", RFC 1042, USC/Information - Sciences Institute, February 1988. - - [17] Sun Microsystems, "System and Network Administration", March - 1990. - - [18] Mills, D., "Internet Time Synchronization: The Network Time - Protocol", RFC 1305, UDEL, March 1992. - - [19] NetBIOS Working Group, "Protocol Standard for a NetBIOS Service - on a TCP/UDP transport: Concepts and Methods", STD 19, RFC 1001, - March 1987. - - [20] NetBIOS Working Group, "Protocol Standard for a NetBIOS Service - on a TCP/UDP transport: Detailed Specifications", STD 19, RFC - 1002, March 1987. - - [21] Scheifler, R., "FYI On the X Window System", FYI 6, RFC 1198, - MIT Laboratory for Computer Science, January 1991. - - [22] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700, - USC/Information Sciences Institute, July 1992. - -13. Security Considerations - - Security issues are not discussed in this memo. - - - - - - - - - - - - - - - - - - -Alexander & Droms Standards Track [Page 33] - -RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997 - - -14. Authors' Addresses - - Steve Alexander - Silicon Graphics, Inc. - 2011 N. Shoreline Boulevard - Mailstop 510 - Mountain View, CA 94043-1389 - - Phone: (415) 933-6172 - EMail: sca@engr.sgi.com - - - Ralph Droms - Bucknell University - Lewisburg, PA 17837 - - Phone: (717) 524-1145 - EMail: droms@bucknell.edu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Alexander & Droms Standards Track [Page 34] - diff --git a/ext/picotcp/RFC/rfc2140.txt b/ext/picotcp/RFC/rfc2140.txt deleted file mode 100644 index 200671c..0000000 --- a/ext/picotcp/RFC/rfc2140.txt +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - -Network Working Group J. Touch -Request for Comments: 2140 ISI -Category: Informational April 1997 - - - TCP Control Block Interdependence - -Status of this Memo - - This memo provides information for the Internet community. This memo - does not specify an Internet standard of any kind. Distribution of - this memo is unlimited. - - -Abstract - - This memo makes the case for interdependent TCP control blocks, where - part of the TCP state is shared among similar concurrent connections, - or across similar connection instances. TCP state includes a - combination of parameters, such as connection state, current round- - trip time estimates, congestion control information, and process - information. This state is currently maintained on a per-connection - basis in the TCP control block, but should be shared across - connections to the same host. The goal is to improve transient - transport performance, while maintaining backward-compatibility with - existing implementations. - - This document is a product of the LSAM project at ISI. - - -Introduction - - TCP is a connection-oriented reliable transport protocol layered over - IP [9]. Each TCP connection maintains state, usually in a data - structure called the TCP Control Block (TCB). The TCB contains - information about the connection state, its associated local process, - and feedback parameters about the connection's transmission - properties. As originally specified and usually implemented, the TCB - is maintained on a per-connection basis. This document discusses the - implications of that decision, and argues for an alternate - implementation that shares some of this state across similar - connection instances and among similar simultaneous connections. The - resulting implementation can have better transient performance, - especially for numerous short-lived and simultaneous connections, as - often used in the World-Wide Web [1]. These changes affect only the - TCB initialization, and so have no effect on the long-term behavior - of TCP after a connection has been established. - - - - -Touch Informational [Page 1] - -RFC 2140 TCP Control Block Interdependence April 1997 - - -The TCP Control Block (TCB) - - A TCB is associated with each connection, i.e., with each association - of a pair of applications across the network. The TCB can be - summarized as containing [9]: - - - Local process state - - pointers to send and receive buffers - pointers to retransmission queue and current segment - pointers to Internet Protocol (IP) PCB - - Per-connection shared state - - macro-state - - connection state - timers - flags - local and remote host numbers and ports - - micro-state - - send and receive window state (size*, current number) - round-trip time and variance - cong. window size* - cong. window size threshold* - max windows seen* - MSS# - round-trip time and variance# - - - The per-connection information is shown as split into macro-state and - micro-state, terminology borrowed from [5]. Macro-state describes the - finite state machine; we include the endpoint numbers and components - (timers, flags) used to help maintain that state. This includes the - protocol for establishing and maintaining shared state about the - connection. Micro-state describes the protocol after a connection has - been established, to maintain the reliability and congestion control - of the data transferred in the connection. - - We further distinguish two other classes of shared micro-state that - are associated more with host-pairs than with application pairs. One - class is clearly host-pair dependent (#, e.g., MSS, RTT), and the - other is host-pair dependent in its aggregate (*, e.g., cong. window - info., curr. window sizes). - - - - -Touch Informational [Page 2] - -RFC 2140 TCP Control Block Interdependence April 1997 - - -TCB Interdependence - - The observation that some TCB state is host-pair specific rather than - application-pair dependent is not new, and is a common engineering - decision in layered protocol implementations. A discussion of sharing - RTT information among protocols layered over IP, including UDP and - TCP, occurred in [8]. T/TCP uses caches to maintain TCB information - across instances, e.g., smoothed RTT, RTT variance, congestion - avoidance threshold, and MSS [3]. These values are in addition to - connection counts used by T/TCP to accelerate data delivery prior to - the full three-way handshake during an OPEN. The goal is to aggregate - TCB components where they reflect one association - that of the - host-pair, rather than artificially separating those components by - connection. - - At least one current T/TCP implementation saves the MSS and - aggregates the RTT parameters across multiple connections, but omits - caching the congestion window information [4], as originally - specified in [2]. There may be other values that may be cached, such - as current window size, to permit new connections full access to - accumulated channel resources. - - We observe that there are two cases of TCB interdependence. Temporal - sharing occurs when the TCB of an earlier (now CLOSED) connection to - a host is used to initialize some parameters of a new connection to - that same host. Ensemble sharing occurs when a currently active - connection to a host is used to initialize another (concurrent) - connection to that host. T/TCP documents considered the temporal - case; we consider both. - -An Example of Temporal Sharing - - Temporal sharing of cached TCB data has been implemented in the SunOS - 4.1.3 T/TCP extensions [4] and the FreeBSD port of same [7]. As - mentioned before, only the MSS and RTT parameters are cached, as - originally specified in [2]. Later discussion of T/TCP suggested - including congestion control parameters in this cache [3]. - - The cache is accessed in two ways: it is read to initialize new TCBs, - and written when more current per-host state is available. New TCBs - are initialized as follows; snd_cwnd reuse is not yet implemented, - although discussed in the T/TCP concepts [2]: - - - - - - - - - -Touch Informational [Page 3] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - TEMPORAL SHARING - TCB Initialization - - Cached TCB New TCB - ---------------------------------------- - old-MSS old-MSS - - old-RTT old-RTT - - old-RTTvar old-RTTvar - - old-snd_cwnd old-snd_cwnd (not yet impl.) - - - Most cached TCB values are updated when a connection closes. An - exception is MSS, which is updated whenever the MSS option is - received in a TCP header. - - - TEMPORAL SHARING - Cache Updates - - Cached TCB Current TCB when? New Cached TCB - --------------------------------------------------------------- - old-MSS curr-MSS MSSopt curr-MSS - - old-RTT curr-RTT CLOSE old += (curr - old) >> 2 - - old-RTTvar curr-RTTvar CLOSE old += (curr - old) >> 2 - - old-snd_cwnd curr-snd_cwnd CLOSE curr-snd_cwnd (not yet impl.) - - MSS caching is trivial; reported values are cached, and the most - recent value is used. The cache is updated when the MSS option is - received, so the cache always has the most recent MSS value from any - connection. The cache is consulted only at connection establishment, - and not otherwise updated, which means that MSS options do not affect - current connections. The default MSS is never saved; only reported - MSS values update the cache, so an explicit override is required to - reduce the MSS. - - RTT values are updated by a more complicated mechanism [3], [8]. - Dynamic RTT estimation requires a sequence of RTT measurements, even - though a single T/TCP transaction may not accumulate enough samples. - As a result, the cached RTT (and its variance) is an average of its - previous value with the contents of the currently active TCB for that - host, when a TCB is closed. RTT values are updated only when a - connection is closed. Further, the method for averaging the RTT - values is not the same as the method for computing the RTT values - within a connection, so that the cached value may not be appropriate. - - - -Touch Informational [Page 4] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - For temporal sharing, the cache requires updating only when a - connection closes, because the cached values will not yet be used to - initialize a new TCB. For the ensemble sharing, this is not the case, - as discussed below. - - Other TCB variables may also be cached between sequential instances, - such as the congestion control window information. Old cache values - can be overwritten with the current TCB estimates, or a MAX or MIN - function can be used to merge the results, depending on the optimism - or pessimism of the reused values. For example, the congestion window - can be reused if there are no concurrent connections. - -An Example of Ensemble Sharing - - Sharing cached TCB data across concurrent connections requires - attention to the aggregate nature of some of the shared state. - Although MSS and RTT values can be shared by copying, it may not be - appropriate to copy congestion window information. At this point, we - present only the MSS and RTT rules: - - - ENSEMBLE SHARING - TCB Initialization - - Cached TCB New TCB - ---------------------------------- - old-MSS old-MSS - - old-RTT old-RTT - - old-RTTvar old-RTTvar - - - - ENSEMBLE SHARING - Cache Updates - - Cached TCB Current TCB when? New Cached TCB - ----------------------------------------------------------- - old-MSS curr-MSS MSSopt curr-MSS - - old-RTT curr-RTT update rtt_update(old,curr) - - old-RTTvar curr-RTTvar update rtt_update(old,curr) - - - For ensemble sharing, TCB information should be cached as early as - possible, sometimes before a connection is closed. Otherwise, opening - multiple concurrent connections may not result in TCB data sharing if - no connection closes before others open. An optimistic solution would - - - -Touch Informational [Page 5] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - be to update cached data as early as possible, rather than only when - a connection is closing. Some T/TCP implementations do this for MSS - when the TCP MSS header option is received [4], although it is not - addressed specifically in the concepts or functional specification - [2][3]. - - In current T/TCP, RTT values are updated only after a CLOSE, which - does not benefit concurrent sessions. As mentioned in the temporal - case, averaging values between concurrent connections requires - incorporating new RTT measurements. The amount of work involved in - updating the aggregate average should be minimized, but the resulting - value should be equivalent to having all values measured within a - single connection. The function "rtt_update" in the ensemble sharing - table indicates this operation, which occurs whenever the RTT would - have been updated in the individual TCP connection. As a result, the - cache contains the shared RTT variables, which no longer need to - reside in the TCB [8]. - - Congestion window size aggregation is more complicated in the - concurrent case. When there is an ensemble of connections, we need - to decide how that ensemble would have shared the congestion window, - in order to derive initial values for new TCBs. Because concurrent - connections between two hosts share network paths (usually), they - also share whatever capacity exists along that path. With regard to - congestion, the set of connections might behave as if it were - multiplexed prior to TCP, as if all data were part of a single - connection. As a result, the current window sizes would maintain a - constant sum, presuming sufficient offered load. This would go beyond - caching to truly sharing state, as in the RTT case. - - We pause to note that any assumption of this sharing can be - incorrect, including this one. In current implementations, new - congestion windows are set at an initial value of one segment, so - that the sum of the current windows is increased for any new - connection. This can have detrimental consequences where several - connections share a highly congested link, such as in trans-Atlantic - Web access. - - There are several ways to initialize the congestion window in a new - TCB among an ensemble of current connections to a host, as shown - below. Current TCP implementations initialize it to one segment [9], - and T/TCP hinted that it should be initialized to the old window size - [3]. In the former, the assumption is that new connections should - behave as conservatively as possible. In the latter, no accommodation - is made to concurrent aggregate behavior. - - In either case, the sum of window sizes can increase, rather than - remain constant. Another solution is to give each pending connection - - - -Touch Informational [Page 6] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - its "fair share" of the available congestion window, and let the - connections balance from there. The assumption we make here is that - new connections are implicit requests for an equal share of available - link bandwidth which should be granted at the expense of current - connections. This may or may not be the appropriate function; we - propose that it be examined further. - - - ENSEMBLE SHARING - TCB Initialization - Some Options for Sharing Window-size - - Cached TCB New TCB - ----------------------------------------------------------------- - old-snd_cwnd (current) one segment - - (T/TCP hint) old-snd_cwnd - - (proposed) old-snd_cwnd/(N+1) - subtract old-snd_cwnd/(N+1)/N - from each concurrent - - - ENSEMBLE SHARING - Cache Updates - - Cached TCB Current TCB when? New Cached TCB - ---------------------------------------------------------------- - old-snd_cwnd curr-snd_cwnd update (adjust sum as appropriate) - - -Compatibility Issues - - Current TCP implementations do not use TCB caching, with the - exception of T/TCP variants [4][7]. New connections use the default - initial values of all non-instantiated TCB variables. As a result, - each connection calculates its own RTT measurements, MSS value, and - congestion information. Eventually these values are updated for each - connection. - - For the congestion and current window information, the initial values - may not be consistent with the long-term aggregate behavior of a set - of concurrent connections. If a single connection has a window of 4 - segments, new connections assume initial windows of 1 segment (the - minimum), although the current connection's window doesn't decrease - to accommodate this additional load. As a result, connections can - mutually interfere. One example of this has been seen on trans- - Atlantic links, where concurrent connections supporting Web traffic - can collide because their initial windows are too large, even when - set at one segment. - - - -Touch Informational [Page 7] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - Because this proposal attempts to anticipate the aggregate steady- - state values of TCB state among a group or over time, it should avoid - the transient effects of new connections. In addition, because it - considers the ensemble and temporal properties of those aggregates, - it should also prevent the transients of short-lived or multiple - concurrent connections from adversely affecting the overall network - performance. We are performing analysis and experiments to validate - these assumptions. - -Performance Considerations - - Here we attempt to optimize transient behavior of TCP without - modifying its long-term properties. The predominant expense is in - maintaining the cached values, or in using per-host state rather than - per-connection state. In cases where performance is affected, - however, we note that the per-host information can be kept in per- - connection copies (as done now), because with higher performance - should come less interference between concurrent connections. - - Sharing TCB state can occur only at connection establishment and - close (to update the cache), to minimize overhead, optimize transient - behavior, and minimize the effect on the steady-state. It is possible - that sharing state during a connection, as in the RTT or window-size - variables, may be of benefit, provided its implementation cost is not - high. - -Implications - - There are several implications to incorporating TCB interdependence - in TCP implementations. First, it may prevent the need for - application-layer multiplexing for performance enhancement [6]. - Protocols like persistent-HTTP avoid connection reestablishment costs - by serializing or multiplexing a set of per-host connections across a - single TCP connection. This avoids TCP's per-connection OPEN - handshake, and also avoids recomputing MSS, RTT, and congestion - windows. By avoiding the so-called, "slow-start restart," performance - can be optimized. Our proposal provides the MSS, RTT, and OPEN - handshake avoidance of T/TCP, and the "slow-start restart avoidance" - of multiplexing, without requiring a multiplexing mechanism at the - application layer. This multiplexing will be complicated when - quality-of-service mechanisms (e.g., "integrated services - scheduling") are provided later. - - Second, we are attempting to push some of the TCP implementation from - the traditional transport layer (in the ISO model [10]), to the - network layer. This acknowledges that some state currently maintained - as per-connection is in fact per-path, which we simplify as per- - host-pair. Transport protocols typically manage per-application-pair - - - -Touch Informational [Page 8] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - associations (per stream), and network protocols manage per-path - associations (routing). Round-trip time, MSS, and congestion - information is more appropriately handled in a network-layer fashion, - aggregated among concurrent connections, and shared across connection - instances. - - An earlier version of RTT sharing suggested implementing RTT state at - the IP layer, rather than at the TCP layer [8]. Our observations are - for sharing state among TCP connections, which avoids some of the - difficulties in an IP-layer solution. One such problem is determining - the associated prior outgoing packet for an incoming packet, to infer - RTT from the exchange. Because RTTs are still determined inside the - TCP layer, this is simpler than at the IP layer. This is a case where - information should be computed at the transport layer, but shared at - the network layer. - - We also note that per-host-pair associations are not the limit of - these techniques. It is possible that TCBs could be similarly shared - between hosts on a LAN, because the predominant path can be LAN-LAN, - rather than host-host. - - There may be other information that can be shared between concurrent - connections. For example, knowing that another connection has just - tried to expand its window size and failed, a connection may not - attempt to do the same for some period. The idea is that existing TCP - implementations infer the behavior of all competing connections, - including those within the same host or LAN. One possible - optimization is to make that implicit feedback explicit, via extended - information in the per-host TCP area. - -Security Considerations - - These suggested implementation enhancements do not have additional - ramifications for direct attacks. These enhancements may be - susceptible to denial-of-service attacks if not otherwise secured. - For example, an application can open a connection and set its window - size to 0, denying service to any other subsequent connection between - those hosts. - - TCB sharing may be susceptible to denial-of-service attacks, wherever - the TCB is shared, between connections in a single host, or between - hosts if TCB sharing is implemented on the LAN (see Implications - section). Some shared TCB parameters are used only to create new - TCBs, others are shared among the TCBs of ongoing connections. New - connections can join the ongoing set, e.g., to optimize send window - size among a set of connections to the same host. - - - - - -Touch Informational [Page 9] - -RFC 2140 TCP Control Block Interdependence April 1997 - - - Attacks on parameters used only for initialization affect only the - transient performance of a TCP connection. For short connections, - the performance ramification can approach that of a denial-of-service - attack. E.g., if an application changes its TCB to have a false and - small window size, subsequent connections would experience - performance degradation until their window grew appropriately. - - The solution is to limit the effect of compromised TCB values. TCBs - are compromised when they are modified directly by an application or - transmitted between hosts via unauthenticated means (e.g., by using a - dirty flag). TCBs that are not compromised by application - modification do not have any unique security ramifications. Note that - the proposed parameters for TCB sharing are not currently modifiable - by an application. - - All shared TCBs MUST be validated against default minimum parameters - before used for new connections. This validation would not impact - performance, because it occurs only at TCB initialization. This - limits the effect of attacks on new connections, to reducing the - benefit of TCB sharing, resulting in the current default TCP - performance. For ongoing connections, the effect of incoming packets - on shared information should be both limited and validated against - constraints before use. This is a beneficial precaution for existing - TCP implementations as well. - - TCBs modified by an application SHOULD not be shared, unless the new - connection sharing the compromised information has been given - explicit permission to use such information by the connection API. No - mechanism for that indication currently exists, but it could be - supported by an augmented API. This sharing restriction SHOULD be - implemented in both the host and the LAN. Sharing on a LAN SHOULD - utilize authentication to prevent undetected tampering of shared TCB - parameters. These restrictions limit the security impact of modified - TCBs both for connection initialization and for ongoing connections. - - Finally, shared values MUST be limited to performance factors only. - Other information, such as TCP sequence numbers, when shared, are - already known to compromise security. - -Acknowledgements - - The author would like to thank the members of the High-Performance - Computing and Communications Division at ISI, notably Bill Manning, - Bob Braden, Jon Postel, Ted Faber, and Cliff Neuman for their - assistance in the development of this memo. - - - - - - -Touch Informational [Page 10] - -RFC 2140 TCP Control Block Interdependence April 1997 - - -References - - [1] Berners-Lee, T., et al., "The World-Wide Web," Communications of - the ACM, V37, Aug. 1994, pp. 76-82. - - [2] Braden, R., "Transaction TCP -- Concepts," RFC-1379, - USC/Information Sciences Institute, September 1992. - - [3] Braden, R., "T/TCP -- TCP Extensions for Transactions Functional - Specification," RFC-1644, USC/Information Sciences Institute, - July 1994. - - [4] Braden, B., "T/TCP -- Transaction TCP: Source Changes for Sun OS - 4.1.3,", Release 1.0, USC/ISI, September 14, 1994. - - [5] Comer, D., and Stevens, D., Internetworking with TCP/IP, V2, - Prentice-Hall, NJ, 1991. - - [6] Fielding, R., et al., "Hypertext Transfer Protocol -- HTTP/1.1," - Work in Progress. - - [7] FreeBSD source code, Release 2.10, . - - [8] Jacobson, V., (mail to public list "tcp-ip", no archive found), - 1986. - - [9] Postel, Jon, "Transmission Control Protocol," Network Working - Group RFC-793/STD-7, ISI, Sept. 1981. - - [10] Tannenbaum, A., Computer Networks, Prentice-Hall, NJ, 1988. - -Author's Address - - Joe Touch - University of Southern California/Information Sciences Institute - 4676 Admiralty Way - Marina del Rey, CA 90292-6695 - USA - Phone: +1 310-822-1511 x151 - Fax: +1 310-823-6714 - URL: http://www.isi.edu/~touch - Email: touch@isi.edu - - - - - - - - - -Touch Informational [Page 11] - diff --git a/ext/picotcp/RFC/rfc2347.txt b/ext/picotcp/RFC/rfc2347.txt deleted file mode 100644 index dbc0f8c..0000000 --- a/ext/picotcp/RFC/rfc2347.txt +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - -Network Working Group G. Malkin -Request for Commments: 2347 Bay Networks -Updates: 1350 A. Harkin -Obsoletes: 1782 Hewlett Packard Co. -Category: Standards Track May 1998 - - - TFTP Option Extension - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -Abstract - - The Trivial File Transfer Protocol [1] is a simple, lock-step, file - transfer protocol which allows a client to get or put a file onto a - remote host. This document describes a simple extension to TFTP to - allow option negotiation prior to the file transfer. - -Introduction - - The option negotiation mechanism proposed in this document is a - backward-compatible extension to the TFTP protocol. It allows file - transfer options to be negotiated prior to the transfer using a - mechanism which is consistent with TFTP's Request Packet format. The - mechanism is kept simple by enforcing a request-respond-acknowledge - sequence, similar to the lock-step approach taken by TFTP itself. - - While the option negotiation mechanism is general purpose, in that - many types of options may be negotiated, it was created to support - the Blocksize option defined in [2]. Additional options are defined - in [3]. - -Packet Formats - - TFTP options are appended to the Read Request and Write Request - packets. A new type of TFTP packet, the Option Acknowledgment - (OACK), is used to acknowledge a client's option negotiation request. - A new error code, 8, is hereby defined to indicate that a transfer - - - -Malkin & Harkin Standards Track [Page 1] - -RFC 2347 TFTP Option Extension May 1998 - - - should be terminated due to option negotiation. - - Options are appended to a TFTP Read Request or Write Request packet - as follows: - - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> - | opc |filename| 0 | mode | 0 | opt1 | 0 | value1 | 0 | < - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> - - >-------+---+---~~---+---+ - < optN | 0 | valueN | 0 | - >-------+---+---~~---+---+ - - opc - The opcode field contains either a 1, for Read Requests, or 2, - for Write Requests, as defined in [1]. - - filename - The name of the file to be read or written, as defined in [1]. - This is a NULL-terminated field. - - mode - The mode of the file transfer: "netascii", "octet", or "mail", - as defined in [1]. This is a NULL-terminated field. - - opt1 - The first option, in case-insensitive ASCII (e.g., blksize). - This is a NULL-terminated field. - - value1 - The value associated with the first option, in case- - insensitive ASCII. This is a NULL-terminated field. - - optN, valueN - The final option/value pair. Each NULL-terminated field is - specified in case-insensitive ASCII. - - The options and values are all NULL-terminated, in keeping with the - original request format. If multiple options are to be negotiated, - they are appended to each other. The order in which options are - specified is not significant. The maximum size of a request packet - is 512 octets. - - The OACK packet has the following format: - - - - - - - -Malkin & Harkin Standards Track [Page 2] - -RFC 2347 TFTP Option Extension May 1998 - - - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - - opc - The opcode field contains a 6, for Option Acknowledgment. - - opt1 - The first option acknowledgment, copied from the original - request. - - value1 - The acknowledged value associated with the first option. If - and how this value may differ from the original request is - detailed in the specification for the option. - - optN, valueN - The final option/value acknowledgment pair. - -Negotiation Protocol - - The client appends options at the end of the Read Request or Write - request packet, as shown above. Any number of options may be - specified; however, an option may only be specified once. The order - of the options is not significant. - - If the server supports option negotiation, and it recognizes one or - more of the options specified in the request packet, the server may - respond with an Options Acknowledgment (OACK). Each option the - server recognizes, and accepts the value for, is included in the - OACK. Some options may allow alternate values to be proposed, but - this is an option specific feature. The server must not include in - the OACK any option which had not been specifically requested by the - client; that is, only the client may initiate option negotiation. - Options which the server does not support should be omitted from the - OACK; they should not cause an ERROR packet to be generated. If the - value of a supported option is invalid, the specification for that - option will indicate whether the server should simply omit the option - from the OACK, respond with an alternate value, or send an ERROR - packet, with error code 8, to terminate the transfer. - - An option not acknowledged by the server must be ignored by the - client and server as if it were never requested. If multiple options - were requested, the client must use those options which were - acknowledged by the server and must not use those options which were - not acknowledged by the server. - - - - - -Malkin & Harkin Standards Track [Page 3] - -RFC 2347 TFTP Option Extension May 1998 - - - When the client appends options to the end of a Read Request packet, - three possible responses may be returned by the server: - - OACK - acknowledge of Read Request and the options; - - DATA - acknowledge of Read Request, but not the options; - - ERROR - the request has been denied. - - When the client appends options to the end of a Write Request packet, - three possible responses may be returned by the server: - - OACK - acknowledge of Write Request and the options; - - ACK - acknowledge of Write Request, but not the options; - - ERROR - the request has been denied. - - If a server implementation does not support option negotiation, it - will likely ignore any options appended to the client's request. In - this case, the server will return a DATA packet for a Read Request - and an ACK packet for a Write Request establishing normal TFTP data - transfer. In the event that a server returns an error for a request - which carries an option, the client may attempt to repeat the request - without appending any options. This implementation option would - handle servers which consider extraneous data in the request packet - to be erroneous. - - Depending on the original transfer request there are two ways for a - client to confirm acceptance of a server's OACK. If the transfer was - initiated with a Read Request, then an ACK (with the data block - number set to 0) is sent by the client to confirm the values in the - server's OACK packet. If the transfer was initiated with a Write - Request, then the client begins the transfer with the first DATA - packet, using the negotiated values. If the client rejects the OACK, - then it sends an ERROR packet, with error code 8, to the server and - the transfer is terminated. - - Once a client acknowledges an OACK, with an appropriate non-error - response, that client has agreed to use only the options and values - returned by the server. Remember that the server cannot request an - option; it can only respond to them. If the client receives an OACK - containing an unrequested option, it should respond with an ERROR - packet, with error code 8, and terminate the transfer. - - - - - - - -Malkin & Harkin Standards Track [Page 4] - -RFC 2347 TFTP Option Extension May 1998 - - -Examples - - Read Request - - client server - ------------------------------------------------------- - |1|foofile|0|octet|0|blksize|0|1432|0| --> RRQ - <-- |6|blksize|0|1432|0| OACK - |4|0| --> ACK - <-- |3|1| 1432 octets of data | DATA - |4|1| --> ACK - <-- |3|2| 1432 octets of data | DATA - |4|2| --> ACK - <-- |3|3|<1432 octets of data | DATA - |4|3| --> ACK - - Write Request - - client server - ------------------------------------------------------- - |2|barfile|0|octet|0|blksize|0|2048|0| --> RRQ - <-- |6|blksize|0|2048|0| OACK - |3|1| 2048 octets of data | --> DATA - <-- |4|1| ACK - |3|2| 2048 octets of data | --> DATA - <-- |4|2| ACK - |3|3|<2048 octets of data | --> DATA - <-- |4|3| ACK - -Security Considerations - - The basic TFTP protocol has no security mechanism. This is why it - has no rename, delete, or file overwrite capabilities. This document - does not add any security to TFTP; however, the specified extensions - do not add any additional security risks. - -References - - [1] Sollins, K., "The TFTP Protocol (Revision 2)", STD 33, RFC 1350, - October 1992. - - [2] Malkin, G., and A. Harkin, "TFTP Blocksize Option", RFC 2348, - May 1998. - - [3] Malkin, G., and A. Harkin, "TFTP Timeout Interval and Transfer - Size Options", RFC 2349, May 1998. - - - - - -Malkin & Harkin Standards Track [Page 5] - -RFC 2347 TFTP Option Extension May 1998 - - -Authors' Addresses - - Gary Scott Malkin - Bay Networks - 8 Federal Street - Billerica, MA 01821 - - Phone: (978) 916-4237 - EMail: gmalkin@baynetworks.com - - - Art Harkin - Internet Services Project - Information Networks Division - 19420 Homestead Road MS 43LN - Cupertino, CA 95014 - - Phone: (408) 447-3755 - EMail: ash@cup.hp.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Malkin & Harkin Standards Track [Page 6] - -RFC 2347 TFTP Option Extension May 1998 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Malkin & Harkin Standards Track [Page 7] - diff --git a/ext/picotcp/RFC/rfc2349.txt b/ext/picotcp/RFC/rfc2349.txt deleted file mode 100644 index 31abb3e..0000000 --- a/ext/picotcp/RFC/rfc2349.txt +++ /dev/null @@ -1,283 +0,0 @@ - - - - - - -Network Working Group G. Malkin -Request for Commments: 2349 Bay Networks -Updates: 1350 A. Harkin -Obsoletes: 1784 Hewlett Packard Co. -Category: Standards Track May 1998 - - - TFTP Timeout Interval and Transfer Size Options - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -Abstract - - The Trivial File Transfer Protocol [1] is a simple, lock-step, file - transfer protocol which allows a client to get or put a file onto a - remote host. - - This document describes two TFTP options. The first allows the client - and server to negotiate the Timeout Interval. The second allows the - side receiving the file to determine the ultimate size of the - transfer before it begins. The TFTP Option Extension mechanism is - described in [2]. - -Timeout Interval Option Specification - - The TFTP Read Request or Write Request packet is modified to include - the timeout option as follows: - - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - | opc |filename| 0 | mode | 0 | timeout| 0 | #secs | 0 | - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - - opc - The opcode field contains either a 1, for Read Requests, or 2, - for Write Requests, as defined in [1]. - - - - - - -Malkin & Harkin Standards Track [Page 1] - -RFC 2349 TFTP Timeout Interval and Transfer Size Options May 1998 - - - filename - The name of the file to be read or written, as defined in [1]. - This is a NULL-terminated field. - - mode - The mode of the file transfer: "netascii", "octet", or "mail", - as defined in [1]. This is a NULL-terminated field. - - timeout - The Timeout Interval option, "timeout" (case in-sensitive). - This is a NULL-terminated field. - - #secs - The number of seconds to wait before retransmitting, specified - in ASCII. Valid values range between "1" and "255" seconds, - inclusive. This is a NULL-terminated field. - - For example: - - +-------+--------+---+--------+---+--------+---+-------+---+ - | 1 | foobar | 0 | octet | 0 | timeout| 0 | 1 | 0 | - +-------+--------+---+--------+---+--------+---+-------+---+ - - is a Read Request, for the file named "foobar", in octet (binary) - transfer mode, with a timeout interval of 1 second. - - If the server is willing to accept the timeout option, it sends an - Option Acknowledgment (OACK) to the client. The specified timeout - value must match the value specified by the client. - -Transfer Size Option Specification - - The TFTP Read Request or Write Request packet is modified to include - the tsize option as follows: - - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - | opc |filename| 0 | mode | 0 | tsize | 0 | size | 0 | - +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - - opc - The opcode field contains either a 1, for Read Requests, or 2, - for Write Requests, as defined in [1]. - - filename - The name of the file to be read or written, as defined in [1]. - This is a NULL-terminated field. - - - - - -Malkin & Harkin Standards Track [Page 2] - -RFC 2349 TFTP Timeout Interval and Transfer Size Options May 1998 - - - mode - The mode of the file transfer: "netascii", "octet", or "mail", - as defined in [1]. This is a NULL-terminated field. - - tsize - The Transfer Size option, "tsize" (case in-sensitive). This is - a NULL-terminated field. - - size - The size of the file to be transfered. This is a NULL- - terminated field. - - For example: - - +-------+--------+---+--------+---+--------+---+--------+---+ - | 2 | foobar | 0 | octet | 0 | tsize | 0 | 673312 | 0 | - +-------+--------+---+--------+---+--------+---+--------+---+ - - is a Write Request, with the 673312-octet file named "foobar", in - octet (binary) transfer mode. - - In Read Request packets, a size of "0" is specified in the request - and the size of the file, in octets, is returned in the OACK. If the - file is too large for the client to handle, it may abort the transfer - with an Error packet (error code 3). In Write Request packets, the - size of the file, in octets, is specified in the request and echoed - back in the OACK. If the file is too large for the server to handle, - it may abort the transfer with an Error packet (error code 3). - -Security Considerations - - The basic TFTP protocol has no security mechanism. This is why it - has no rename, delete, or file overwrite capabilities. This document - does not add any security to TFTP; however, the specified extensions - do not add any additional security risks. - -References - - [1] Sollins, K., "The TFTP Protocol (Revision 2)", STD 33, RFC 1350, - October 92. - - [2] Malkin, G., and A. Harkin, "TFTP Option Extension", RFC 2347, - May 1998. - - - - - - - - -Malkin & Harkin Standards Track [Page 3] - -RFC 2349 TFTP Timeout Interval and Transfer Size Options May 1998 - - -Authors' Addresses - - Gary Scott Malkin - Bay Networks - 8 Federal Street - Billerica, MA 01821 - - Phone: (978) 916-4237 - EMail: gmalkin@baynetworks.com - - - Art Harkin - Internet Services Project - Information Networks Division - 19420 Homestead Road MS 43LN - Cupertino, CA 95014 - - Phone: (408) 447-3755 - EMail: ash@cup.hp.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Malkin & Harkin Standards Track [Page 4] - -RFC 2349 TFTP Timeout Interval and Transfer Size Options May 1998 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Malkin & Harkin Standards Track [Page 5] - diff --git a/ext/picotcp/RFC/rfc2385.txt b/ext/picotcp/RFC/rfc2385.txt deleted file mode 100644 index deeb0de..0000000 --- a/ext/picotcp/RFC/rfc2385.txt +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - -Network Working Group A. Heffernan -Request for Comments: 2385 cisco Systems -Category: Standards Track August 1998 - - - Protection of BGP Sessions via the TCP MD5 Signature Option - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -IESG Note - - This document describes currrent existing practice for securing BGP - against certain simple attacks. It is understood to have security - weaknesses against concerted attacks. - -Abstract - - This memo describes a TCP extension to enhance security for BGP. It - defines a new TCP option for carrying an MD5 [RFC1321] digest in a - TCP segment. This digest acts like a signature for that segment, - incorporating information known only to the connection end points. - Since BGP uses TCP as its transport, using this option in the way - described in this paper significantly reduces the danger from certain - security attacks on BGP. - -1.0 Introduction - - The primary motivation for this option is to allow BGP to protect - itself against the introduction of spoofed TCP segments into the - connection stream. Of particular concern are TCP resets. - - To spoof a connection using the scheme described in this paper, an - attacker would not only have to guess TCP sequence numbers, but would - also have had to obtain the password included in the MD5 digest. - This password never appears in the connection stream, and the actual - form of the password is up to the application. It could even change - - - - - -Heffernan Standards Track [Page 1] - -RFC 2385 TCP MD5 Signature Option August 1998 - - - during the lifetime of a particular connection so long as this change - was synchronized on both ends (although retransmission can become - problematical in some TCP implementations with changing passwords). - - Finally, there is no negotiation for the use of this option in a - connection, rather it is purely a matter of site policy whether or - not its connections use the option. - -2.0 Proposal - - Every segment sent on a TCP connection to be protected against - spoofing will contain the 16-byte MD5 digest produced by applying the - MD5 algorithm to these items in the following order: - - 1. the TCP pseudo-header (in the order: source IP address, - destination IP address, zero-padded protocol number, and - segment length) - 2. the TCP header, excluding options, and assuming a checksum of - zero - 3. the TCP segment data (if any) - 4. an independently-specified key or password, known to both TCPs - and presumably connection-specific - - The header and pseudo-header are in network byte order. The nature - of the key is deliberately left unspecified, but it must be known by - both ends of the connection. A particular TCP implementation will - determine what the application may specify as the key. - - Upon receiving a signed segment, the receiver must validate it by - calculating its own digest from the same data (using its own key) and - comparing the two digest. A failing comparison must result in the - segment being dropped and must not produce any response back to the - sender. Logging the failure is probably advisable. - - Unlike other TCP extensions (e.g., the Window Scale option - [RFC1323]), the absence of the option in the SYN,ACK segment must not - cause the sender to disable its sending of signatures. This - negotiation is typically done to prevent some TCP implementations - from misbehaving upon receiving options in non-SYN segments. This is - not a problem for this option, since the SYN,ACK sent during - connection negotiation will not be signed and will thus be ignored. - The connection will never be made, and non-SYN segments with options - will never be sent. More importantly, the sending of signatures must - be under the complete control of the application, not at the mercy of - the remote host not understanding the option. - - - - - - -Heffernan Standards Track [Page 2] - -RFC 2385 TCP MD5 Signature Option August 1998 - - -3.0 Syntax - - The proposed option has the following format: - - +---------+---------+-------------------+ - | Kind=19 |Length=18| MD5 digest... | - +---------+---------+-------------------+ - | | - +---------------------------------------+ - | | - +---------------------------------------+ - | | - +-------------------+-------------------+ - | | - +-------------------+ - - The MD5 digest is always 16 bytes in length, and the option would - appear in every segment of a connection. - -4.0 Some Implications - -4.1 Connectionless Resets - - A connectionless reset will be ignored by the receiver of the reset, - since the originator of that reset does not know the key, and so - cannot generate the proper signature for the segment. This means, - for example, that connection attempts by a TCP which is generating - signatures to a port with no listener will time out instead of being - refused. Similarly, resets generated by a TCP in response to - segments sent on a stale connection will also be ignored. - Operationally this can be a problem since resets help BGP recover - quickly from peer crashes. - -4.2 Performance - - The performance hit in calculating digests may inhibit the use of - this option. Some measurements of a sample implementation showed - that on a 100 MHz R4600, generating a signature for simple ACK - segment took an average of 0.0268 ms, while generating a signature - for a data segment carrying 4096 bytes of data took 0.8776 ms on - average. These times would be applied to both the input and output - paths, with the input path also bearing the cost of a 16-byte - compare. - - - - - - - - -Heffernan Standards Track [Page 3] - -RFC 2385 TCP MD5 Signature Option August 1998 - - -4.3 TCP Header Size - - As with other options that are added to every segment, the size of - the MD5 option must be factored into the MSS offered to the other - side during connection negotiation. Specifically, the size of the - header to subtract from the MTU (whether it is the MTU of the - outgoing interface or IP's minimal MTU of 576 bytes) is now at least - 18 bytes larger. - - The total header size is also an issue. The TCP header specifies - where segment data starts with a 4-bit field which gives the total - size of the header (including options) in 32-byte words. This means - that the total size of the header plus option must be less than or - equal to 60 bytes -- this leaves 40 bytes for options. - - As a concrete example, 4.4BSD defaults to sending window-scaling and - timestamp information for connections it initiates. The most loaded - segment will be the initial SYN packet to start the connection. With - MD5 signatures, the SYN packet will contain the following: - - -- 4 bytes MSS option - -- 4 bytes window scale option (3 bytes padded to 4 in 4.4BSD) - -- 12 bytes for timestamp (4.4BSD pads the option as recommended - in RFC 1323 Appendix A) - -- 18 bytes for MD5 digest - -- 2 bytes for end-of-option-list, to pad to a 32-bit boundary. - - This sums to 40 bytes, which just makes it. - -4.4 MD5 as a Hashing Algorithm - - Since this memo was first issued (under a different title), the MD5 - algorithm has been found to be vulnerable to collision search attacks - [Dobb], and is considered by some to be insufficiently strong for - this type of application. - - This memo still specifies the MD5 algorithm, however, since the - option has already been deployed operationally, and there was no - "algorithm type" field defined to allow an upgrade using the same - option number. The original document did not specify a type field - since this would require at least one more byte, and it was felt at - the time that taking 19 bytes for the complete option (which would - probably be padded to 20 bytes in TCP implementations) would be too - much of a waste of the already limited option space. - - - - - - - -Heffernan Standards Track [Page 4] - -RFC 2385 TCP MD5 Signature Option August 1998 - - - This does not prevent the deployment of another similar option which - uses another hashing algorithm (like SHA-1). Also, if most - implementations pad the 18 byte option as defined to 20 bytes anyway, - it would be just as well to define a new option which contains an - algorithm type field. - - This would need to be addressed in another document, however. - -4.5 Key configuration - - It should be noted that the key configuration mechanism of routers - may restrict the possible keys that may be used between peers. It is - strongly recommended that an implementation be able to support at - minimum a key composed of a string of printable ASCII of 80 bytes or - less, as this is current practice. - -5.0 Security Considerations - - This document defines a weak but currently practiced security - mechanism for BGP. It is anticipated that future work will provide - different stronger mechanisms for dealing with these issues. - -6.0 References - - [RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm," RFC 1321, - April 1992. - - [RFC1323] Jacobson, V., Braden, R., and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [Dobb] H. Dobbertin, "The Status of MD5 After a Recent Attack", RSA - Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996. - http://www.rsa.com/rsalabs/pubs/cryptobytes.html - -Author's Address - - Andy Heffernan - cisco Systems - 170 West Tasman Drive - San Jose, CA 95134 USA - - Phone: +1 408 526-8115 - EMail: ahh@cisco.com - - - - - - - - -Heffernan Standards Track [Page 5] - -RFC 2385 TCP MD5 Signature Option August 1998 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Heffernan Standards Track [Page 6] - diff --git a/ext/picotcp/RFC/rfc2398.txt b/ext/picotcp/RFC/rfc2398.txt deleted file mode 100644 index ece738a..0000000 --- a/ext/picotcp/RFC/rfc2398.txt +++ /dev/null @@ -1,843 +0,0 @@ - - - - - - -Network Working Group S. Parker -Request for Comments: 2398 C. Schmechel -FYI: 33 Sun Microsystems, Inc. -Category: Informational August 1998 - - - Some Testing Tools for TCP Implementors - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -1. Introduction - - Available tools for testing TCP implementations are catalogued by - this memo. Hopefully disseminating this information will encourage - those responsible for building and maintaining TCP to make the best - use of available tests. The type of testing the tool provides, the - type of tests it is capable of doing, and its availability is - enumerated. This document lists only tools which can evaluate one or - more TCP implementations, or which can privde some specific results - which describe or evaluate the TCP being tested. A number of these - tools produce time-sequence plots, see - - Tim Shepard's thesis [She91] for a general discussion of these plots. - - Each tools is defined as follows: - - Name - - The name associated with the testing tool. - - Category - - One or more categories of tests which the tools are capable of - providing. Categories used are: functional correctness, performance, - stress. Functional correctness tests how stringent a TCP - implementation is to the RFC specifications. Performance tests how - - - - - - - -Parker & Schmechel Informational [Page 1] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - quickly a TCP implementation can send and receive data, etc. Stress - tests how a TCP implementation is effected under high load - conditions. - - Description - - A description of the tools construction, and the implementation - methodology of the tests. - - Automation - - What steps are required to complete the test? What human - intervention is required? - - Availability - - How do you retrieve this tool and get more information about it? - - Required Environment - - Compilers, OS version, etc. required to build and/or run the - associated tool. - - References - - A list of publications relating to the tool, if any. - -2. Tools - -2.1. Dbs - - Author - Yukio Murayama - - Category - Performance / Stress - - Description - Dbs is a tool which allows multiple data transfers to be coordinated, - and the resulting TCP behavior to be reviewed. Results are presented - as ASCII log files. - - Automation - Command of execution is driven by a script file. - - - - - - - -Parker & Schmechel Informational [Page 2] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - Availability - See http://www.ai3.net/products/dbs for details of precise OS - versions supported, and for download of the source code. Current - implementation supports BSDI BSD/OS, Linux, mkLinux, SunOS, IRIX, - Ultrix, NEWS OS, HP-UX. Other environments are likely easy to add. - - Required Environment - C language compiler, UNIX-style socket API support. - -2.2. Dummynet - - Author - Luigi Rizzo - - Category - Functional Correctness / Performance - - Description - Dummynet is a tool which simulates the presence of finite size - queues, bandwidth limitations, and communication delays. Dummynet - inserts between two layers of the protocol stack (in the current - implementation between TCP and IP), simulating the above effects in - an operational system. This way experiments can be done using real - protocol implementations and real applications, even running on the - same host (dummynet also intercepts communications on the loopback - interface). Reconfiguration of dummynet parameters (delay, queue - size, bandwidth) can be done on the fly by using a sysctl call. The - overhead of dummynet is extremely low. - - Automation - Requires merging diff files with kernel source code. Command-line - driven through the sysctl command to modify kernel variables. - - Availability - See http://www.iet.unipi.it/~luigi/research.html or e-mail Luigi - Rizzo (l.rizzo@iet.unipi.it). Source code is available for FreeBSD - 2.1 and FreeBSD 2.2 (easily adaptable to other BSD-derived systems). - - Required Environment - C language compiler, BSD-derived system, kernel source code. - - References - [Riz97] - - - - - - - - -Parker & Schmechel Informational [Page 3] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -2.3. Netperf - - Author - Rick Jones - - Category - Performance - - Description - Single connection bandwidth or latency tests for TCP, UDP, and DLPI. - Includes provisions for CPU utilization measurement. - - Automation - Requires compilation (K&R C sufficient for all but-DHISTOGRAM, may - require ANSI C in the future) if starting from source. Execution as - child of inetd requires editing of /etc/services and /etc/inetd.conf. - Scripts are provided for a quick look (snapshot_script), bulk - throughput of TCP and UDP, and latency for TCP and UDP. It is - command-line driven. - - Availability - See http://www.cup.hp.com/netperf/NetperfPage.html or e-mail Rick - Jones (raj@cup.hp.com). Binaries are available here for HP/UX Irix, - Solaris, and Win32. - - Required Environment - C language compiler, POSIX.1, sockets. - -2.4. NIST Net - - Author - Mark Carson - - Category - Functional Correctness / Performance - - Description - NIST Net is a network emulator. The tool is packaged as a Linux - kernel patch, a kernel module, a set of programming APIs, and - command-line and X-based user interfaces. - - NIST Net works by turning the system into a "selectively bad" router - - incoming packets may be delayed, dropped, duplicated, bandwidth- - constrained, etc. Packet delays may be fixed or randomly - distributed, with loadable probability distributions. Packet loss - may be uniformly distributed (constant loss probability) or - congestion-dependent (probability of loss increases with packet queue - lengths). Explicit congestion notifications may optionally be sent - - - -Parker & Schmechel Informational [Page 4] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - in place of congestion-dependent loss. - - Automation - To control the operation of the emulator, there is an interactive - user interface, a non-interactive command-line interface, and a set - of APIs. Any or all of these may be used in concert. The - interactive interface is suitable for simple, spur-of-the-moment - testing, while the command-line or APIs may be used to create - scripted, non-interactive tests. - - Availability - NIST Net is available for public download from the NIST Net web site, - http://www.antd.nist.gov/itg/nistnet/. The web site also has - installation instructions and documentation. - - Required Environment - NIST Net requires a Linux installtion, with kernel version 2.0.27 - - 2.0.33. A kernel source tree and build tools are required to build - and install the NIST Net components. Building the X interface - requires a version of XFree86 (Current Version is 3.3.2). An - Athena-replacement widget set such as neXtaw - (http://www.inf.ufrgs.br/~kojima/nextaw/) is also desirable for an - improved user interface. - - NIST Net should run on any i386-compatible machine capable of running - Linux, with one or more interfaces. - -2.5. Orchestra - - Author - Scott Dawson, Farnam Jahanian, and Todd Mitton - - Category - Functional Correctness / Performance - - Description - This tool is a library which provides the user with an ability to - build a protocol layer capable of performing fault injection on - protocols. Several fault injection layers have been built using this - library, one of which has been used to test different vendor - implementations of TCP. This is accomplished by probing the vendor - implementation from one machine containing a protocol stack that has - been instrumented with Orchestra. A connection is opened from the - vendor TCP implementation to the machine which has been instrumented. - Faults may then be injected at the Orchestra side of the connection - and the vendor TCP's response may be monitored. The most recent - version of Orchestra runs inside the X-kernel protocol stack on the - OSF MK operating system. - - - -Parker & Schmechel Informational [Page 5] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - When using Orchestra to test a protocol, the fault injection layer is - placed below the target protocol in the protocol stack. This can - either be done on one machine on the network, if protocol stacks on - the other machines cannot be modified (as in the case of testing - TCP), or can be done on all machines on the network (as in the case - of testing a protocol under development). Once the fault injection - layer is in the protocol stack, all messages sent by and destined for - the target protocol pass through it on their way to/from the network. - The Orchestra fault injection layer can manipulate these messages. - In particular, it can drop, delay, re-order, duplicate, or modify - messages. It can also introduce new messages into the system if - desired. - - The actions of the Orchestra fault injection layer on each message - are determined by a script, written in Tcl. This script is - interpreted by the fault injection layer when the message enters the - layer. The script has access to the header information about the - message, and can make decisions based on header values. It can also - keep information about previous messages, counters, or any other data - which the script writer deems useful. Users of Orchestra may also - define their own actions to be taken on messages, written in C, that - may be called from the fault injection scripts. - - Automation - Scripts can be specified either using a graphical user interface - which generates Tcl, or by writing Tcl directly. At this time, - post-analysis of the results of the test must also be performed by - the user. Essentially this consists of looking at a packet trace - that Orchestra generates for (in)correct behavior. Must compile and - link fault generated layer with the protocol stack. - - Availability - See http://www.eecs.umich.edu/RTCL/projects/orchestra/ or e-mail - Scott Dawson (sdawson@eecs.umich.edu). - - Required Environment OSF MK operating system, or X-kernel like network - architecture, or adapted to network stack. - - References - [DJ94], [DJM96a], [DJM96b] - - - - - - - - - - - -Parker & Schmechel Informational [Page 6] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -2.6. Packet Shell - - Author - Steve Parker and Chris Schmechel - - Category - Functional Correctness / Performance - - Description - An extensible Tcl/Tk based software toolset for protocol development - and testing. Tcl (Tool Command Language) is an embeddable scripting - language and Tk is a graphical user interface toolkit based on Tcl. - The Packet Shell creates Tcl commands that allow you to create, - modify, send, and receive packets on networks. The operations for - each protocol are supplied by a dynamic linked library called a - protocol library. These libraries are silently linked in from a - special directory when the Packet Shell begins execution. The current - protocol libraries are: IP, IPv6, IPv6 extensions, ICMP, ICMPv6, - Ethernet layer, data layer, file layer (snoop and tcpdump support), - socket layer, TCP, TLI. - - It includes harness, which is a Tk based graphical user interface for - creating test scripts within the Packet Shell. It includes tests for - no initial slow start, and retain out of sequence data as TCP test - cases mentioned in [PADHV98]. - - It includes tcpgraph, which is used with a snoop or tcpdump capture - file to produce a TCP time-sequence plot using xplot. - - Automation - Command-line driven through Tcl commands, or graphical user interface - models are available through the harness format. - - Availability - See http://playground.sun.com/psh/ or e-mail owner-packet- - shell@sunroof.eng.sun.com. - - Required Environment - - Solaris 2.4 or higher. Porting required for other operating systems. - - - - - - - - - - - -Parker & Schmechel Informational [Page 7] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -2.7. Tcpanaly - - Author - Vern Paxson - - Category - Functional Correctness / Performance - - Description - This is a tool for automatically analyzing a TCP implementation's - behavior by inspecting packet traces of the TCP's activity. It does - so through packet filter traces produced by tcpdump. It has coded - within it knowledge of a large number of TCP implementations. Using - this, it can determine whether a given trace appears consistent with - a given implementation, and, if so, exactly why the TCP chose to - transmit each packet at the time it did. If a trace is found - inconsistent with a TCP, tcpanaly either diagnoses a likely - measurement error present in the trace, or indicates exactly whether - the activity in the trace deviates from that of the TCP, which can - greatly aid in determining how the traced implementation behaves. - - Tcpanaly's category is somewhat difficult to classify, since it - attempts to profile the behavior of an implementation, rather than to - explicitly test specific correctness or performance issues. However, - this profile identifies correctness and performance problems. - - Adding new implementations of TCP behavior is possible with tcpanaly - through the use of C++ classes. - - Automation - Command-line driven and only the traces of the TCP sending and - receiving bulk data transfers are needed as input. - - Availability - Contact Vern Paxson (vern@ee.lbl.gov). - - Required Environment - C++ compiler. - - References - [Pax97a] - - - - - - - - - - -Parker & Schmechel Informational [Page 8] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -2.8. Tcptrace - - Author - Shawn Ostermann - - Category - Functional Correctness / Performance - - Description - This is a TCP trace file analysis tool. It reads output trace files - in the formats of : tcpdump, snoop, etherpeek, and netm. - - For each connection, it keeps track of elapsed time, bytes/segments - sent and received, retransmissions, round trip times, window - advertisements, throughput, etc from simple to very detailed output. - - It can also produce three different types of graphs: - - Time Sequence Graph (shows the segments sent and ACKs returned as a - function of time) - - Instantaneous Throughput (shows the instantaneous, averaged over a - few segments, throughput of the connection as a function of time). - - Round Trip Times (shows the round trip times for the ACKs as a - function of time) - - Automation - Command-line driven, and uses the xplot program to view the graphs. - - Availability - Source code is available, and Solaris binary along with sample - traces. See http://jarok.cs.ohiou.edu/software/tcptrace/tcptrace.html - or e-mail Shawn Ostermann (ostermann@cs.ohiou.edu). - - Required Environment - C compiler, Solaris, FreeBSD, NetBSD, HPUX, Linux. - - - - - - - - - - - - - - -Parker & Schmechel Informational [Page 9] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -2.9. Tracelook - - Author - Greg Minshall - - Category - Functional Correctness / Performance - - Description - This is a Tcl/Tk program for graphically viewing the contents of - tcpdump trace files. When plotting a connection, a user can select - various variables to be plotted. In each direction of the connection, - the user can plot the advertised window in each packet, the highest - sequence number in each packet, the lowest sequence number in each - packet, and the acknowledgement number in each packet. - - Automation - Command-line driven with a graphical user interface for the graph. - - Availability - See http://www.ipsilon.com/~minshall/sw/tracelook/tracelook.html or - e-mail Greg Minshall (minshall@ipsilon.com). - - Required Environment - A modern version of awk, and Tcl/Tk (Tk version 3.6 or higher). The - program xgraph is required to view the graphs under X11. - -2.10. TReno - - Author - Matt Mathis and Jamshid Mahdavi - - Category - Performance - - Description - This is a TCP throughput measurement tool based on sending UDP or - ICMP packets in patterns that are controlled at the user-level so - that their timing reflects what would be sent by a TCP that observes - proper congestion control (and implements SACK). This allows it to - measure throughput independent of the TCP implementation of end hosts - and serve as a useful platform for prototyping TCP changes. - - Automation - Command-line driven. No "server" is required, and it only requires a - single argument of the machine to run the test to. - - - - - -Parker & Schmechel Informational [Page 10] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - Availability - See http://www.psc.edu/networking/treno_info.html or e-mail Matt - Mathis (mathis@psc.edu) or Jamshid Mahdavi (mahdavi@psc.edu). - - Required Environment - C compiler, POSIX.1, raw sockets. - -2.11. Ttcp - - Author - Unknown - - Category - Performance - - Description - Originally written to move files around, ttcp became the classic - throughput benchmark or load generator, with the addition of support - for sourcing to/from memory. It can also be used as a traffic - absorber. It has spawned many variants, recent ones include support - for UDP, data pattern generation, page alignment, and even alignment - offset control. - - Automation - Command-line driven. - - Availability - See ftp://ftp.arl.mil/pub/ttcp/ or e-mail ARL (ftp@arl.mil) which - includes the most common variants available. - - Required Environment - C compiler, BSD sockets. - -2.12. Xplot - - Author - Tim Shepard - - Category - Functional Correctness / Performance - - Description - This is a fairly conventional graphing/plotting tool (xplot itself), - a script to turn tcpdump output into xplot input, and some sample - code to generate xplot commands to plot the TCP time-sequence graph). - - Automation - Command-line driven with a graphical user interface for the plot. - - - -Parker & Schmechel Informational [Page 11] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - Availability - See ftp://mercury.lcs.mit.edu/pub/shep/xplot.tar.gz or e-mail Tim - Shepard (shep@lcs.mit.edu). - - Required Environment - C compiler, X11. - - References - [She91] - -3. Summary - - This memo lists all TCP tests and testing tools reported to the - authors as part of TCP Implementer's working group and is not - exhaustive. These tools have been verified as available by the - authors. - -4. Security Considerations - - Network analysis tools are improving at a steady pace. The - continuing improvement in these tools such as the ones described make - security concerns significant. - - Some of the tools could be used to create rogue packets or denial- - of-service attacks against other hosts. Also, some of the tools - require changes to the kernel (foreign code) and might require root - privileges to execute. So you are trusting code that you have - fetched from some perhaps untrustworthy remote site. This code could - contain malicious code that could present any kind of attack. - - None of the listed tools evaluate security in any way or form. - - There are privacy concerns when grabbing packets from the network in - that you are now able to read other people's mail, files, etc. This - impacts more than just the host running the tool but all traffic - crossing the host's physical network. - -5. References - - [DJ94] Scott Dawson and Farnam Jahanian, "Probing and Fault - Injection of Distributed Protocol Implementations", - University of Michigan Technical Report CSE-TR-217-94, EECS - Department. - - [DJM96a] Scott Dawson, Farnam Jahanian, and Todd Mitton, "ORCHESTRA: - A Fault Injection Environment for Distributed Systems", - University of Michigan Technical Report CSE-TR-318-96, EECS - Department. - - - -Parker & Schmechel Informational [Page 12] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - - [DJM96b] Scott Dawson, Farnam Jahanian, and Todd Mitton, - "Experiments on Six Commercial TCP Implementations Using a - Software Fault Injection Tool", University of Michigan - Technical Report CSE-TR-298-96, EECS Department. - - [Pax97a] Vern Paxson, "Automated Packet Trace Analysis of TCP - Implementations", ACM SIGCOMM '97, September 1997, Cannes, - France. - - [PADHV98] Paxson, V., Allman, M., Dawson, S., Heavens, I., and B. - Volz, "Known TCP Implementation Problems", Work In - Progress. - - [Riz97] Luigi Rizzo, "Dummynet: a simple approach to the evaluation - of network protocols", ACM Computer Communication Review, - Vol. 27, N. 1, January 1997, pp. 31-41. - - [She91] Tim Shepard, "TCP Packet Trace Analysis", MIT Laboratory - for Computer Science MIT-LCS-TR-494, February, 1991. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Parker & Schmechel Informational [Page 13] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -6. Authors' Addresses - - Steve Parker - Sun Microsystems, Inc. - 901 San Antonio Road, UMPK17-202 - Palo Alto, CA 94043 - USA - - Phone: (650) 786-5176 - EMail: sparker@eng.sun.com - - - Chris Schmechel - Sun Microsystems, Inc. - 901 San Antonio Road, UMPK17-202 - Palo Alto, CA, 94043 - USA - - Phone: (650) 786-4053 - EMail: cschmec@eng.sun.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Parker & Schmechel Informational [Page 14] - -RFC 2398 Some Testing Tools for TCP Implementors August 1998 - - -7. Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Parker & Schmechel Informational [Page 15] - diff --git a/ext/picotcp/RFC/rfc2415.txt b/ext/picotcp/RFC/rfc2415.txt deleted file mode 100644 index a5506ee..0000000 --- a/ext/picotcp/RFC/rfc2415.txt +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - -Network Working Group K. Poduri -Request for Comments: 2415 K. Nichols -Category: Informational Bay Networks - September 1998 - - - Simulation Studies of Increased Initial TCP Window Size - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -Abstract - - An increase in the permissible initial window size of a TCP - connection, from one segment to three or four segments, has been - under discussion in the tcp-impl working group. This document covers - some simulation studies of the effects of increasing the initial - window size of TCP. Both long-lived TCP connections (file transfers) - and short-lived web-browsing style connections were modeled. The - simulations were performed using the publicly available ns-2 - simulator and our custom models and files are also available. - -1. Introduction - - We present results from a set of simulations with increased TCP - initial window (IW). The main objectives were to explore the - conditions under which the larger IW was a "win" and to determine the - effects, if any, the larger IW might have on other traffic flows - using an IW of one segment. - - This study was inspired by discussions at the Munich IETF tcp-impl - and tcp-sat meetings. A proposal to increase the IW size to about 4K - bytes (4380 bytes in the case of 1460 byte segments) was discussed. - Concerns about both the utility of the increase and its effect on - other traffic were raised. Some studies were presented showing the - positive effects of increased IW on individual connections, but no - studies were shown with a wide variety of simultaneous traffic flows. - It appeared that some of the questions being raised could be - addressed in an ns-2 simulation. Early results from our simulations - were previously posted to the tcp-impl mailing list and presented at - the tcp-impl WG meeting at the December 1997 IETF. - - - -Poduri & Nichols Informational [Page 1] - -RFC 2415 TCP Window Size September 1998 - - -2. Model and Assumptions - - We simulated a network topology with a bottleneck link as shown: - - 10Mb, 10Mb, - (all 4 links) (all 4 links) - - C n2_________ ______ n6 S - l n3_________\ /______ n7 e - i \\ 1.5Mb, 50ms // r - e n0 ------------------------ n1 v - n n4__________// \ \_____ n8 e - t n5__________/ \______ n9 r - s s - - URLs --> <--- FTP & Web data - - File downloading and web-browsing clients are attached to the nodes - (n2-n5) on the left-hand side. These clients are served by the FTP - and Web servers attached to the nodes (n6-n9) on the right-hand side. - The links to and from those nodes are at 10 Mbps. The bottleneck link - is between n1 and n0. All links are bi-directional, but only ACKs, - SYNs, FINs, and URLs are flowing from left to right. Some simulations - were also performed with data traffic flowing from right to left - simultaneously, but it had no effect on the results. - - In the simulations we assumed that all ftps transferred 1-MB files - and that all web pages had exactly three embedded URLs. The web - clients are browsing quite aggressively, requesting a new page after - a random delay uniformly distributed between 1 and 5 seconds. This is - not meant to realistically model a single user's web-browsing - pattern, but to create a reasonably heavy traffic load whose - individual tcp connections accurately reflect real web traffic. Some - discussion of these models as used in earlier studies is available in - references [3] and [4]. - - The maximum tcp window was set to 11 packets, maximum packet (or - segment) size to 1460 bytes, and buffer sizes were set at 25 packets. - (The ns-2 TCPs require setting window sizes and buffer sizes in - number of packets. In our tcp-full code some of the internal - parameters have been set to be byte-oriented, but external values - must still be set in number of packets.) In our simulations, we - varied the number of data segments sent into a new TCP connection (or - initial window) from one to four, keeping all segments at 1460 bytes. - A dropped packet causes a restart window of one segment to be used, - just as in current practice. - - - - - -Poduri & Nichols Informational [Page 2] - -RFC 2415 TCP Window Size September 1998 - - - For ns-2 users: The tcp-full code was modified to use an - "application" class and three application client-server pairs were - written: a simple file transfer (ftp), a model of http1.0 style web - connection and a very rough model of http1.1 style web connection. - The required files and scripts for these simulations are available - under the contributed code section on the ns-simulator web page at - the sites ftp://ftp.ee.lbl.gov/IW.{tar, tar.Z} or http://www- - nrg.ee.lbl.gov/floyd/tcp_init_win.html. - - Simulations were run with 8, 16, 32 web clients and a number of ftp - clients ranging from 0 to 3. The IW was varied from 1 to 4, though - the 4-packet case lies beyond what is currently recommended. The - figures of merit used were goodput, the median page delay seen by the - web clients and the median file transfer delay seen by the ftp - clients. The simulated run time was rather large, 360 seconds, to - ensure an adequate sample. (Median values remained the same for - simulations with larger run times and can be considered stable) - -3. Results - - In our simulations, we varied the number of file transfer clients in - order to change the congestion of the link. Recall that our ftp - clients continuously request 1 Mbyte transfers, so the link - utilization is over 90% when even a single ftp client is present. - When three file transfer clients are running simultaneously, the - resultant congestion is somewhat pathological, making the values - recorded stable. Though all connections use the same initial window, - the effect of increasing the IW on a 1 Mbyte file transfer is not - detectable, thus we focus on the web browsing connections. (In the - tables, we use "webs" to indicate number of web clients and "ftps" to - indicate the number of file transfer clients attached.) Table 1 shows - the median delays experienced by the web transfers with an increase - in the TCP IW. There is clearly an improvement in transfer delays - for the web connections with increase in the IW, in many cases on the - order of 30%. The steepness of the performance improvement going - from an IW of 1 to an IW of 2 is mainly due to the distribution of - files fetched by each URL (see references [1] and [2]); the median - size of both primary and in-line URLs fits completely into two - packets. If file distributions change, the shape of this curve may - also change. - - - - - - - - - - - -Poduri & Nichols Informational [Page 3] - -RFC 2415 TCP Window Size September 1998 - - - Table 1. Median web page delay - - #Webs #FTPs IW=1 IW=2 IW=3 IW=4 - (s) (% decrease) - ---------------------------------------------- - 8 0 0.56 14.3 17.9 16.1 - 8 1 1.06 18.9 25.5 32.1 - 8 2 1.18 16.1 17.1 28.9 - 8 3 1.26 11.9 19.0 27.0 - 16 0 0.64 11.0 15.6 18.8 - 16 1 1.04 17.3 24.0 35.6 - 16 2 1.22 17.2 20.5 25.4 - 16 3 1.31 10.7 21.4 22.1 - 32 0 0.92 17.6 28.6 21.0 - 32 1 1.19 19.6 25.0 26.1 - 32 2 1.43 23.8 35.0 33.6 - 32 3 1.56 19.2 29.5 33.3 - - Table 2 shows the bottleneck link utilization and packet drop - percentage of the same experiment. Packet drop rates did increase - with IW, but in all cases except that of the single most pathological - overload, the increase in drop percentage was less than 1%. A - decrease in packet drop percentage is observed in some overloaded - situations, specifically when ftp transfers consumed most of the link - bandwidth and a large number of web transfers shared the remaining - bandwidth of the link. In this case, the web transfers experience - severe packet loss and some of the IW=4 web clients suffer multiple - packet losses from the same window, resulting in longer recovery - times than when there is a single packet loss in a window. During the - recovery time, the connections are inactive which alleviates - congestion and thus results in a decrease in the packet drop - percentage. It should be noted that such observations were made only - in extremely overloaded scenarios. - - - - - - - - - - - - - - - - - - -Poduri & Nichols Informational [Page 4] - -RFC 2415 TCP Window Size September 1998 - - -Table 2. Link utilization and packet drop rates - - Percentage Link Utilization | Packet drop rate -#Webs #FTPs IW=1 IW=2 IW=3 IW=4 |IW=1 IW=2 IW=3 IW=4 ------------------------------------------------------------------------ - 8 0 34 37 38 39 | 0.0 0.0 0.0 0.0 - 8 1 95 92 93 92 | 0.6 1.2 1.4 1.3 - 8 2 98 97 97 96 | 1.8 2.3 2.3 2.7 - 8 3 98 98 98 98 | 2.6 3.0 3.5 3.5 ------------------------------------------------------------------------ - 16 0 67 69 69 67 | 0.1 0.5 0.8 1.0 - 16 1 96 95 93 92 | 2.1 2.6 2.9 2.9 - 16 2 98 98 97 96 | 3.5 3.6 4.2 4.5 - 16 3 99 99 98 98 | 4.5 4.7 5.2 4.9 ------------------------------------------------------------------------ - 32 0 92 87 85 84 | 0.1 0.5 0.8 1.0 - 32 1 98 97 96 96 | 2.1 2.6 2.9 2.9 - 32 2 99 99 98 98 | 3.5 3.6 4.2 4.5 - 32 3 100 99 99 98 | 9.3 8.4 7.7 7.6 - - To get a more complete picture of performance, we computed the - network power, goodput divided by median delay (in Mbytes/ms), and - plotted it against IW for all scenarios. (Each scenario is uniquely - identified by its number of webs and number of file transfers.) We - plot these values in Figure 1 (in the pdf version), illustrating a - general advantage to increasing IW. When a large number of web - clients is combined with ftps, particularly multiple ftps, - pathological cases result from the extreme congestion. In these - cases, there appears to be no particular trend to the results of - increasing the IW, in fact simulation results are not particularly - stable. - - To get a clearer picture of what is happening across all the tested - scenarios, we normalized the network power values for the non- - pathological scenario by the network power for that scenario at IW of - one. These results are plotted in Figure 2. As IW is increased from - one to four, network power increased by at least 15%, even in a - congested scenario dominated by bulk transfer traffic. In simulations - where web traffic has a dominant share of the available bandwidth, - the increase in network power was up to 60%. - - The increase in network power at higher initial window sizes is due - to an increase in throughput and a decrease in the delay. Since the - (slightly) increased drop rates were accompanied by better - performance, drop rate is clearly not an indicator of user level - performance. - - - - - -Poduri & Nichols Informational [Page 5] - -RFC 2415 TCP Window Size September 1998 - - - The gains in performance seen by the web clients need to be balanced - against the performance the file transfers are seeing. We computed - ftp network power and show this in Table 3. It appears that the - improvement in network power seen by the web connections has - negligible effect on the concurrent file transfers. It can be - observed from the table that there is a small variation in the - network power of file transfers with an increase in the size of IW - but no particular trend can be seen. It can be concluded that the - network power of file transfers essentially remained the same. - However, it should be noted that a larger IW does allow web transfers - to gain slightly more bandwidth than with a smaller IW. This could - mean fewer bytes transferred for FTP applications or a slight - decrease in network power as computed by us. - - Table 3. Network power of file transfers with an increase in the TCP - IW size - - #Webs #FTPs IW=1 IW=2 IW=3 IW=4 - -------------------------------------------- - 8 1 4.7 4.2 4.2 4.2 - 8 2 3.0 2.8 3.0 2.8 - 8 3 2.2 2.2 2.2 2.2 - 16 1 2.3 2.4 2.4 2.5 - 16 2 1.8 2.0 1.8 1.9 - 16 3 1.4 1.6 1.5 1.7 - 32 1 0.7 0.9 1.3 0.9 - 32 2 0.8 1.0 1.3 1.1 - 32 3 0.7 1.0 1.2 1.0 - - The above simulations all used http1.0 style web connections, thus, a - natural question is to ask how results are affected by migration to - http1.1. A rough model of this behavior was simulated by using one - connection to send all of the information from both the primary URL - and the three embedded, or in-line, URLs. Since the transfer size is - now made up of four web files, the steep improvement in performance - between an IW of 1 and an IW of two, noted in the previous results, - has been smoothed. Results are shown in Tables 4 & 5 and Figs. 3 & 4. - Occasionally an increase in IW from 3 to 4 decreases the network - power owing to a non-increase or a slight decrease in the throughput. - TCP connections opening up with a higher window size into a very - congested network might experience some packet drops and consequently - a slight decrease in the throughput. This indicates that increase of - the initial window sizes to further higher values (>4) may not always - result in a favorable network performance. This can be seen clearly - in Figure 4 where the network power shows a decrease for the two - highly congested cases. - - - - - -Poduri & Nichols Informational [Page 6] - -RFC 2415 TCP Window Size September 1998 - - - Table 4. Median web page delay for http1.1 - - #Webs #FTPs IW=1 IW=2 IW=3 IW=4 - (s) (% decrease) - ---------------------------------------------- - 8 0 0.47 14.9 19.1 21.3 - 8 1 0.84 17.9 19.0 25.0 - 8 2 0.99 11.5 17.3 23.0 - 8 3 1.04 12.1 20.2 28.3 - 16 0 0.54 07.4 14.8 20.4 - 16 1 0.89 14.6 21.3 27.0 - 16 2 1.02 14.7 19.6 25.5 - 16 3 1.11 09.0 17.0 18.9 - 32 0 0.94 16.0 29.8 36.2 - 32 1 1.23 12.2 28.5 21.1 - 32 2 1.39 06.5 13.7 12.2 - 32 3 1.46 04.0 11.0 15.0 - - - Table 5. Network power of file transfers with an increase in the - TCP IW size - - #Webs #FTPs IW=1 IW=2 IW=3 IW=4 - -------------------------------------------- - 8 1 4.2 4.2 4.2 3.7 - 8 2 2.7 2.5 2.6 2.3 - 8 3 2.1 1.9 2.0 2.0 - 16 1 1.8 1.8 1.5 1.4 - 16 2 1.5 1.2 1.1 1.5 - 16 3 1.0 1.0 1.0 1.0 - 32 1 0.3 0.3 0.5 0.3 - 32 2 0.4 0.3 0.4 0.4 - 32 3 0.4 0.3 0.4 0.5 - - For further insight, we returned to the http1.0 model and mixed some - web-browsing connections with IWs of one with those using IWs of - three. In this experiment, we first simulated a total of 16 web- - browsing connections, all using IW of one. Then the clients were - split into two groups of 8 each, one of which uses IW=1 and the other - used IW=3. - - We repeated the simulations for a total of 32 and 64 web-browsing - clients, splitting those into groups of 16 and 32 respectively. Table - 6 shows these results. We report the goodput (in Mbytes), the web - page delays (in milli seconds), the percent utilization of the link - and the percent of packets dropped. - - - - - -Poduri & Nichols Informational [Page 7] - -RFC 2415 TCP Window Size September 1998 - - -Table 6. Results for half-and-half scenario - -Median Page Delays and Goodput (MB) | Link Utilization (%) & Drops (%) -#Webs IW=1 | IW=3 | IW=1 | IW=3 - G.put dly | G.put dly | L.util Drops| L.util Drops -------------------|-------------------|---------------|--------------- -16 35.5 0.64| 36.4 0.54 | 67 0.1 | 69 0.7 -8/8 16.9 0.67| 18.9 0.52 | 68 0.5 | -------------------|-------------------|---------------|--------------- -32 48.9 0.91| 44.7 0.68 | 92 3.5 | 85 4.3 -16/16 22.8 0.94| 22.9 0.71 | 89 4.6 | -------------------|-------------------|---------------|---------------- -64 51.9 1.50| 47.6 0.86 | 98 13.0 | 91 8.6 -32/32 29.0 1.40| 22.0 1.20 | 98 12.0 | - - Unsurprisingly, the non-split experiments are consistent with our - earlier results, clients with IW=3 outperform clients with IW=1. The - results of running the 8/8 and 16/16 splits show that running a - mixture of IW=3 and IW=1 has no negative effect on the IW=1 - conversations, while IW=3 conversations maintain their performance. - However, the 32/32 split shows that web-browsing connections with - IW=3 are adversely affected. We believe this is due to the - pathological dynamics of this extremely congested scenario. Since - embedded URLs open their connections simultaneously, very large - number of TCP connections are arriving at the bottleneck link - resulting in multiple packet losses for the IW=3 conversations. The - myriad problems of this simultaneous opening strategy is, of course, - part of the motivation for the development of http1.1. - -4. Discussion - - The indications from these results are that increasing the initial - window size to 3 packets (or 4380 bytes) helps to improve perceived - performance. Many further variations on these simulation scenarios - are possible and we've made our simulation models and scripts - available in order to facilitate others' experiments. - - We also used the RED queue management included with ns-2 to perform - some other simulation studies. We have not reported on those results - here since we don't consider the studies complete. We found that by - adding RED to the bottleneck link, we achieved similar performance - gains (with an IW of 1) to those we found with increased IWs without - RED. Others may wish to investigate this further. - - Although the simulation sets were run for a T1 link, several - scenarios with varying levels of congestion and varying number of web - and ftp clients were analyzed. It is reasonable to expect that the - results would scale for links with higher bandwidth. However, - - - -Poduri & Nichols Informational [Page 8] - -RFC 2415 TCP Window Size September 1998 - - - interested readers could investigate this aspect further. - - We also used the RED queue management included with ns-2 to perform - some other simulation studies. We have not reported on those results - here since we don't consider the studies complete. We found that by - adding RED to the bottleneck link, we achieved similar performance - gains (with an IW of 1) to those we found with increased IWs without - RED. Others may wish to investigate this further. - -5. References - - [1] B. Mah, "An Empirical Model of HTTP Network Traffic", Proceedings - of INFOCOM '97, Kobe, Japan, April 7-11, 1997. - - [2] C.R. Cunha, A. Bestavros, M.E. Crovella, "Characteristics of WWW - Client-based Traces", Boston University Computer Science - Technical Report BU-CS-95-010, July 18, 1995. - - [3] K.M. Nichols and M. Laubach, "Tiers of Service for Data Access in - a HFC Architecture", Proceedings of SCTE Convergence Conference, - January, 1997. - - [4] K.M. Nichols, "Improving Network Simulation with Feedback", - available from knichols@baynetworks.com - -6. Acknowledgements - - This work benefited from discussions with and comments from Van - Jacobson. - -7. Security Considerations - - This document discusses a simulation study of the effects of a - proposed change to TCP. Consequently, there are no security - considerations directly related to the document. There are also no - known security considerations associated with the proposed change. - - - - - - - - - - - - - - - -Poduri & Nichols Informational [Page 9] - -RFC 2415 TCP Window Size September 1998 - - -8. Authors' Addresses - - Kedarnath Poduri - Bay Networks - 4401 Great America Parkway - SC01-04 - Santa Clara, CA 95052-8185 - - Phone: +1-408-495-2463 - Fax: +1-408-495-1299 - EMail: kpoduri@Baynetworks.com - - - Kathleen Nichols - Bay Networks - 4401 Great America Parkway - SC01-04 - Santa Clara, CA 95052-8185 - - EMail: knichols@baynetworks.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Poduri & Nichols Informational [Page 10] - -RFC 2415 TCP Window Size September 1998 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Poduri & Nichols Informational [Page 11] - diff --git a/ext/picotcp/RFC/rfc2416.txt b/ext/picotcp/RFC/rfc2416.txt deleted file mode 100644 index b5e3a90..0000000 --- a/ext/picotcp/RFC/rfc2416.txt +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - -Network Working Group T. Shepard -Request for Comments: 2416 C. Partridge -Category: Informational BBN Technologies - September 1998 - - - When TCP Starts Up With Four Packets Into Only Three Buffers - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -Abstract - - This memo is to document a simple experiment. The experiment showed - that in the case of a TCP receiver behind a 9600 bps modem link at - the edge of a fast Internet where there are only 3 buffers before the - modem (and the fourth packet of a four-packet start will surely be - dropped), no significant degradation in performance is experienced by - a TCP sending with a four-packet start when compared with a normal - slow start (which starts with just one packet). - -Background - - Sally Floyd has proposed that TCPs start their initial slow start by - sending as many as four packets (instead of the usual one packet) as - a means of getting TCP up-to-speed faster. (Slow starts instigated - due to timeouts would still start with just one packet.) Starting - with more than one packet might reduce the start-up latency over - long-fat pipes by two round-trip times. This proposal is documented - further in [1], [2], and in [3] and we assume the reader is familiar - with the details of this proposal. - - On the end2end-interest mailing list, concern was raised that in the - (allegedly common) case where a slow modem is served by a router - which only allocates three buffers per modem (one buffer being - transmitted while two packets are waiting), that starting with four - packets would not be good because the fourth packet is sure to be - dropped. - - - - - - -Shepard & Partridge Informational [Page 1] - -RFC 2416 TCP with Four Packets into Three Buffers September 1998 - - - Vern Paxson replied with the comment (among other things) that the - four-packet start is no worse than what happens after two round trip - times in normal slow start, hence no new problem is introduced by - starting with as many as four packets. If there is a problem with a - four-packet start, then the problem already exists in a normal slow- - start startup after two round trip times when the slow-start - algorithm will release into the net four closely spaced packets. - - The experiment reported here confirmed Vern Paxson's reasoning. - -Scenario and experimental setup - - -+--------+ 100 Mbps +---+ 1.5 Mbps +---+ 9600 bps +----------+ -| source +------------+ R +-------------+ R +--------------+ receiver | -+--------+ no delay +---+ 25 ms delay +---+ 150 ms delay +----------+ - - | | - | | - (we spy here) (this router has only 3 buffers - to hold packets going into the - 9600 bps link) - - The scenario studied and simulated consists of three links between - the source and sink. The first link is a 100 Mbps link with no - delay. It connects the sender to a router. (It was included to have - a means of logging the returning ACKs at the time they would be seen - by the sender.) The second link is a 1.5 Mbps link with a 25 ms - one-way delay. (This link was included to roughly model traversing - an un-congested, intra-continental piece of the terrestrial - Internet.) The third link is a 9600 bps link with a 150 ms one-way - delay. It connects the edge of the net to a receiver which is behind - the 9600 bps link. - - The queue limits for the queues at each end of the first two links - were set to 100 (a value sufficiently large that this limit was never - a factor). The queue limits at each end of the 9600 bps link were - set to 3 packets (which can hold at most two packets while one is - being sent). - - Version 1.2a2 of the the NS simulator (available from LBL) was used - to simulate both one-packet and four-packet starts for each of the - available TCP algorithms (tahoe, reno, sack, fack) and the conclusion - reported here is independent of which TCP algorithm is used (in - general, we believe). In this memo, the "tahoe" module will be used - to illustrate what happens. In the 4-packet start cases, the - "window-init" variable was set to 4, and the TCP implementations were - modified to use the value of the window-init variable only on - - - -Shepard & Partridge Informational [Page 2] - -RFC 2416 TCP with Four Packets into Three Buffers September 1998 - - - connection start, but to set cwnd to 1 on other instances of a slow- - start. (The tcp.cc module as shipped with ns-1.2a2 would use the - window-init value in all cases.) - - The packets in simulation are 1024 bytes long for purposes of - determining the time it takes to transmit them through the links. - (The TCP modules included with the LBL NS simulator do not simulate - the TCP sequence number mechanisms. They use just packet numbers.) - - Observations are made of all packets and acknowledgements crossing - the 100 Mbps no-delay link, near the sender. (All descriptions below - are from this point of view.) - -What happens with normal slow start - - At time 0.0 packet number 1 is sent. - - At time 1.222 an ack is received covering packet number 1, and - packets 2 and 3 are sent. - - At time 2.444 an ack is received covering packet number 2, and - packets 4 and 5 are sent. - - At time 3.278 an ack is received covering packet number 3, and - packets 6 and 7 are sent. - - At time 4.111 an ack is received covering packet number 4, and - packets 8 and 9 are sent. - - At time 4.944 an ack is received covering packet number 5, and - packets 10 and 11 are sent. - - At time 5.778 an ack is received covering packet number 6, and - packets 12 and 13 are sent. - - At time 6.111 a duplicate ack is recieved (covering packet number 6). - - At time 7.444 another duplicate ack is received (covering packet - number 6). - - At time 8.278 a third duplicate ack is received (covering packet - number 6) and packet number 7 is retransmitted. - - (And the trace continues...) - -What happens with a four-packet start - - At time 0.0, packets 1, 2, 3, and 4 are sent. - - - -Shepard & Partridge Informational [Page 3] - -RFC 2416 TCP with Four Packets into Three Buffers September 1998 - - - At time 1.222 an ack is received covering packet number 1, and - packets 5 and 6 are sent. - - At time 2.055 an ack is received covering packet number 2, and - packets 7 and 8 are sent. - - At time 2.889 an ack is received covering packet number 3, and - packets 9 and 10 are sent. - - At time 3.722 a duplicate ack is received (covering packet number 3). - - At time 4.555 another duplicate ack is received (covering packet - number 3). - - At time 5.389 a third duplicate ack is received (covering packet - number 3) and packet number 4 is retransmitted. - - (And the trace continues...) - -Discussion - - At the point left off in the two traces above, the two different - systems are in almost identical states. The two traces from that - point on are almost the same, modulo a shift in time of (8.278 - - 5.389) = 2.889 seconds and a shift of three packets. If the normal - TCP (with the one-packet start) will deliver packet N at time T, then - the TCP with the four-packet start will deliver packet N - 3 at time - T - 2.889 (seconds). - - Note that the time to send three 1024-byte TCP segments through a - 9600 bps modem is 2.66 seconds. So at what time does the four- - packet-start TCP deliver packet N? At time T - 2.889 + 2.66 = T - - 0.229 in most cases, and in some cases earlier, in some cases later, - because different packets (by number) experience loss in the two - traces. - - Thus the four-packet-start TCP is in some sense 0.229 seconds (or - about one fifth of a packet) ahead of where the one-packet-start TCP - would be. (This is due to the extra time the modem sits idle while - waiting for the dally timer to go off in the receiver in the case of - the one-packet-start TCP.) - - The states of the two systems are not exactly identical. They differ - slightly in the round-trip-time estimators because the behavior at - the start is not identical. (The observed round trip times may differ - by a small amount due to dally timers and due to that the one-packet - start experiences more round trip times before the first loss.) In - the cases where a retransmit timer did later go off, the additional - - - -Shepard & Partridge Informational [Page 4] - -RFC 2416 TCP with Four Packets into Three Buffers September 1998 - - - difference in timing was much smaller than the 0.229 second - difference discribed above. - -Conclusion - - In this particular case, the four-packet start is not harmful. - -Non-conclusions, opinions, and future work - - A four-packet start would be very helpful in situations where a - long-delay link is involved (as it would reduce transfer times for - moderately-sized transfers by as much as two round-trip times). But - it remains (in the authors' opinions at this time) an open question - whether or not the four-packet start would be safe for the network. - - It would be nice to see if this result could be duplicated with real - TCPs, real modems, and real three-buffer limits. - -Security Considerations - - This document discusses a simulation study of the effects of a - proposed change to TCP. Consequently, there are no security - considerations directly related to the document. There are also no - known security considerations associated with the proposed change. - -References - - 1. S. Floyd, Increasing TCP's Initial Window (January 29, 1997). - URL ftp://ftp.ee.lbl.gov/papers/draft.jan29. - - 2. S. Floyd and M. Allman, Increasing TCP's Initial Window (July, - 1997). URL http://gigahertz.lerc.nasa.gov/~mallman/share/draft- - ss.txt - - 3. Allman, M., Floyd, S., and C. Partridge, "Increasing TCP's - Initial Window", RFC 2414, September 1998. - - - - - - - - - - - - - - - -Shepard & Partridge Informational [Page 5] - -RFC 2416 TCP with Four Packets into Three Buffers September 1998 - - -Authors' Addresses - - Tim Shepard - BBN Technologies - 10 Moulton Street - Cambridge, MA 02138 - - EMail: shep@alum.mit.edu - - - Craig Partridge - BBN Technologies - 10 Moulton Street - Cambridge, MA 02138 - - EMail: craig@bbn.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Shepard & Partridge Informational [Page 6] - -RFC 2416 TCP with Four Packets into Three Buffers September 1998 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Shepard & Partridge Informational [Page 7] - diff --git a/ext/picotcp/RFC/rfc2452.txt b/ext/picotcp/RFC/rfc2452.txt deleted file mode 100644 index dcbcf26..0000000 --- a/ext/picotcp/RFC/rfc2452.txt +++ /dev/null @@ -1,563 +0,0 @@ - - - - - - -Network Working Group M. Daniele -Request for Comments: 2452 Compaq Computer Corporation -Category: Standards Track December 1998 - - - IP Version 6 Management Information Base - for the Transmission Control Protocol - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -Abstract - - This document is one in the series of documents that define various - MIB objects for IPv6. Specifically, this document is the MIB module - which defines managed objects for implementations of the Transmission - Control Protocol (TCP) over IP Version 6 (IPv6). - - This document also recommends a specific policy with respect to the - applicability of RFC 2012 for implementations of IPv6. Namely, that - most of managed objects defined in RFC 2012 are independent of which - IP versions underlie TCP, and only the TCP connection information is - IP version-specific. - - This memo defines an experimental portion of the Management - Information Base (MIB) for use with network management protocols in - IPv6-based internets. - -1. Introduction - - A management system contains: several (potentially many) nodes, each - with a processing entity, termed an agent, which has access to - management instrumentation; at least one management station; and, a - management protocol, used to convey management information between - the agents and management stations. Operations of the protocol are - carried out under an administrative framework which defines - authentication, authorization, access control, and privacy policies. - - - - - -Daniele Standards Track [Page 1] - -RFC 2452 TCP MIB for IPv6 December 1998 - - - Management stations execute management applications which monitor and - control managed elements. Managed elements are devices such as - hosts, routers, terminal servers, etc., which are monitored and - controlled via access to their management information. - - Management information is viewed as a collection of managed objects, - residing in a virtual information store, termed the Management - Information Base (MIB). Collections of related objects are defined - in MIB modules. These modules are written using a subset of OSI's - Abstract Syntax Notation One (ASN.1) [1], termed the Structure of - Management Information (SMI) [2]. - -2. Overview - - This document is one in the series of documents that define various - MIB objects, and statements of conformance, for IPv6. This document - defines the required instrumentation for implementations of TCP over - IPv6. - -3. Transparency of IP versions to TCP - - The fact that a particular TCP connection uses IPv6 as opposed to - IPv4, is largely invisible to a TCP implementation. A "TCPng" did - not need to be defined, implementations simply need to support IPv6 - addresses. - - As such, the managed objects already defined in [TCP MIB] are - sufficient for managing TCP in the presence of IPv6. These objects - are equally applicable whether the managed node supports IPv4 only, - IPv6 only, or both IPv4 and IPv6. - - For example, tcpActiveOpens counts "The number of times TCP - connections have made a direct transition to the SYN-SENT state from - the CLOSED state", regardless of which version of IP is used between - the connection endpoints. - - Stated differently, TCP implementations don't need separate counters - for IPv4 and for IPv6. - -4. Representing TCP Connections - - The exception to the statements in section 3 is the tcpConnTable. - Since IPv6 addresses cannot be represented with the IpAddress syntax, - not all TCP connections can be represented in the tcpConnTable - defined in [TCP MIB]. - - - - - - -Daniele Standards Track [Page 2] - -RFC 2452 TCP MIB for IPv6 December 1998 - - - This memo defines a new, separate table to represent only those TCP - connections between IPv6 endpoints. TCP connections between IPv4 - endpoints continue to be represented in tcpConnTable [TCP MIB]. (It - is not possible to establish a TCP connection between an IPv4 - endpoint and an IPv6 endpoint.) - - A different approach would have been to define a new table to - represent all TCP connections regardless of IP version. This would - require changes to [TCP MIB] and hence to existing (IPv4-only) TCP - implementations. The approach suggested in this memo has the - advantage of leaving IPv4-only implementations intact. - - It is assumed that the objects defined in this memo will eventually - be defined in an update to [TCP MIB]. For this reason, the module - identity is assigned under the experimental portion of the MIB. - -5. Conformance - - This memo contains conformance statements to define conformance to - this MIB for TCP over IPv6 implementations. - -6. Definitions - -IPV6-TCP-MIB DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF - MODULE-IDENTITY, OBJECT-TYPE, - mib-2, experimental FROM SNMPv2-SMI - Ipv6Address, Ipv6IfIndexOrZero FROM IPV6-TC; - -ipv6TcpMIB MODULE-IDENTITY - LAST-UPDATED "9801290000Z" - ORGANIZATION "IETF IPv6 MIB Working Group" - CONTACT-INFO - " Mike Daniele - - Postal: Compaq Computer Corporation - 110 Spitbrook Rd - Nashua, NH 03062. - US - - Phone: +1 603 884 1423 - Email: daniele@zk3.dec.com" - DESCRIPTION - "The MIB module for entities implementing TCP over IPv6." - ::= { experimental 86 } - - - - -Daniele Standards Track [Page 3] - -RFC 2452 TCP MIB for IPv6 December 1998 - - --- objects specific to TCP for IPv6 - -tcp OBJECT IDENTIFIER ::= { mib-2 6 } - --- the TCP over IPv6 Connection table - --- This connection table contains information about this --- entity's existing TCP connections between IPv6 endpoints. --- Only connections between IPv6 addresses are contained in --- this table. This entity's connections between IPv4 --- endpoints are contained in tcpConnTable. - -ipv6TcpConnTable OBJECT-TYPE - SYNTAX SEQUENCE OF Ipv6TcpConnEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table containing TCP connection-specific information, - for only those connections whose endpoints are IPv6 addresses." - ::= { tcp 16 } - -ipv6TcpConnEntry OBJECT-TYPE - SYNTAX Ipv6TcpConnEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A conceptual row of the ipv6TcpConnTable containing - information about a particular current TCP connection. - Each row of this table is transient, in that it ceases to - exist when (or soon after) the connection makes the transition - to the CLOSED state. - - Note that conceptual rows in this table require an additional - index object compared to tcpConnTable, since IPv6 addresses - are not guaranteed to be unique on the managed node." - INDEX { ipv6TcpConnLocalAddress, - ipv6TcpConnLocalPort, - ipv6TcpConnRemAddress, - ipv6TcpConnRemPort, - ipv6TcpConnIfIndex } - ::= { ipv6TcpConnTable 1 } - -Ipv6TcpConnEntry ::= - SEQUENCE { ipv6TcpConnLocalAddress Ipv6Address, - ipv6TcpConnLocalPort INTEGER (0..65535), - ipv6TcpConnRemAddress Ipv6Address, - ipv6TcpConnRemPort INTEGER (0..65535), - ipv6TcpConnIfIndex Ipv6IfIndexOrZero, - - - -Daniele Standards Track [Page 4] - -RFC 2452 TCP MIB for IPv6 December 1998 - - - ipv6TcpConnState INTEGER } - -ipv6TcpConnLocalAddress OBJECT-TYPE - SYNTAX Ipv6Address - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The local IPv6 address for this TCP connection. In - the case of a connection in the listen state which - is willing to accept connections for any IPv6 - address associated with the managed node, the value - ::0 is used." - ::= { ipv6TcpConnEntry 1 } - -ipv6TcpConnLocalPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The local port number for this TCP connection." - ::= { ipv6TcpConnEntry 2 } - -ipv6TcpConnRemAddress OBJECT-TYPE - SYNTAX Ipv6Address - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The remote IPv6 address for this TCP connection." - ::= { ipv6TcpConnEntry 3 } - -ipv6TcpConnRemPort OBJECT-TYPE - SYNTAX INTEGER (0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The remote port number for this TCP connection." - ::= { ipv6TcpConnEntry 4 } - -ipv6TcpConnIfIndex OBJECT-TYPE - SYNTAX Ipv6IfIndexOrZero - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "An index object used to disambiguate conceptual rows in - the table, since the connection 4-tuple may not be unique. - - If the connection's remote address (ipv6TcpConnRemAddress) - is a link-local address and the connection's local address - - - -Daniele Standards Track [Page 5] - -RFC 2452 TCP MIB for IPv6 December 1998 - - - (ipv6TcpConnLocalAddress) is not a link-local address, this - object identifies a local interface on the same link as - the connection's remote link-local address. - - Otherwise, this object identifies the local interface that - is associated with the ipv6TcpConnLocalAddress for this - TCP connection. If such a local interface cannot be determined, - this object should take on the value 0. (A possible example - of this would be if the value of ipv6TcpConnLocalAddress is ::0.) - - The interface identified by a particular non-0 value of this - index is the same interface as identified by the same value - of ipv6IfIndex. - - The value of this object must remain constant during the life - of the TCP connection." - ::= { ipv6TcpConnEntry 5 } - -ipv6TcpConnState OBJECT-TYPE - SYNTAX INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11), - deleteTCB(12) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The state of this TCP connection. - - The only value which may be set by a management station is - deleteTCB(12). Accordingly, it is appropriate for an agent - to return an error response (`badValue' for SNMPv1, 'wrongValue' - for SNMPv2) if a management station attempts to set this - object to any other value. - - If a management station sets this object to the value - deleteTCB(12), then this has the effect of deleting the TCB - (as defined in RFC 793) of the corresponding connection on - the managed node, resulting in immediate termination of the - connection. - - - -Daniele Standards Track [Page 6] - -RFC 2452 TCP MIB for IPv6 December 1998 - - - As an implementation-specific option, a RST segment may be - sent from the managed node to the other TCP endpoint (note - however that RST segments are not sent reliably)." - ::= { ipv6TcpConnEntry 6 } - --- --- conformance information --- - -ipv6TcpConformance OBJECT IDENTIFIER ::= { ipv6TcpMIB 2 } - -ipv6TcpCompliances OBJECT IDENTIFIER ::= { ipv6TcpConformance 1 } -ipv6TcpGroups OBJECT IDENTIFIER ::= { ipv6TcpConformance 2 } - --- compliance statements - -ipv6TcpCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for SNMPv2 entities which - implement TCP over IPv6." - MODULE -- this module - MANDATORY-GROUPS { ipv6TcpGroup } - ::= { ipv6TcpCompliances 1 } - -ipv6TcpGroup OBJECT-GROUP - OBJECTS { -- these are defined in this module - -- ipv6TcpConnLocalAddress (not-accessible) - -- ipv6TcpConnLocalPort (not-accessible) - -- ipv6TcpConnRemAddress (not-accessible) - -- ipv6TcpConnRemPort (not-accessible) - -- ipv6TcpConnIfIndex (not-accessible) - ipv6TcpConnState } - STATUS current - DESCRIPTION - "The group of objects providing management of - TCP over IPv6." - ::= { ipv6TcpGroups 1 } - -END - - - - - - - - - - - -Daniele Standards Track [Page 7] - -RFC 2452 TCP MIB for IPv6 December 1998 - - -7. Acknowledgments - - This memo is a product of the IPng work group, and benefited - especially from the contributions of the following working group - members: - - Dimitry Haskin Bay Networks - Margaret Forsythe Epilogue - Tim Hartrick Mentat - Frank Solensky FTP - Jack McCann DEC - -8. References - - [1] Information processing systems - Open Systems - Interconnection - Specification of Abstract Syntax - Notation One (ASN.1), International Organization for - Standardization. International Standard 8824, - (December, 1987). - - [2] McCloghrie, K., Editor, "Structure of Management - Information for version 2 of the Simple Network - Management Protocol (SNMPv2)", RFC 1902, January 1996. - - [TCP MIB] SNMPv2 Working Group, McCloghrie, K., Editor, "SNMPv2 - Management Information Base for the Transmission - Control Protocol using SMIv2", RFC 2012, November 1996. - - [IPV6 MIB TC] Haskin, D., and S. Onishi, "Management Information - Base for IP Version 6: Textual Conventions and General - Group", RFC 2465, December 1998. - - [IPV6] Deering, S., and R. Hinden, "Internet Protocol, Version - 6 (IPv6) Specification", RFC 2460, December 1998. - - [RFC2274] Blumenthal, U., and B. Wijnen, "The User-Based Security - Model for Version 3 of the Simple Network Management - Protocol (SNMPv3)", RFC 2274, January 1998. - - [RFC2275] Wijnen, B., Presuhn, R., and K. McCloghrie, "View-based - Access Control Model for the Simple Network Management - Protocol (SNMP)", RFC 2275, January 1998. - -9. Security Considerations - - This MIB contains a management object that has a MAX-ACCESS clause of - read-write and/or read-create. In particular, it is possible to - delete individual TCP control blocks (i.e., connections). - - - -Daniele Standards Track [Page 8] - -RFC 2452 TCP MIB for IPv6 December 1998 - - - Consequently, anyone having the ability to issue a SET on this object - can impact the operation of the node. - - There are a number of managed objects in this MIB that may be - considered to contain sensitive information in some environments. - For example, the MIB identifies the active TCP connections on the - node. Although this information might be considered sensitive in - some environments (i.e., to identify ports on which to launch - denial-of-service or other attacks), there are already other ways of - obtaining similar information. For example, sending a random TCP - packet to an unused port prompts the generation of a TCP reset - message. - - Therefore, it may be important in some environments to control read - and/or write access to these objects and possibly to even encrypt the - values of these object when sending them over the network via SNMP. - Not all versions of SNMP provide features for such a secure - environment. SNMPv1 by itself does not provide encryption or strong - authentication. - - It is recommended that the implementors consider the security - features as provided by the SNMPv3 framework. Specifically, the use - of the User-based Security Model [RFC2274] and the View-based Access - Control Model [RFC2275] is recommended. - - It is then a customer/user responsibility to ensure that the SNMP - entity giving access to an instance of this MIB, is properly - configured to give access to those objects only to those principals - (users) that have legitimate rights to access them. - -10. Author's Address - - Mike Daniele - Compaq Computer Corporation - 110 Spit Brook Rd - Nashua, NH 03062 - - Phone: +1-603-884-1423 - EMail: daniele@zk3.dec.com - - - - - - - - - - - - -Daniele Standards Track [Page 9] - -RFC 2452 TCP MIB for IPv6 December 1998 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Daniele Standards Track [Page 10] - diff --git a/ext/picotcp/RFC/rfc2474.txt b/ext/picotcp/RFC/rfc2474.txt deleted file mode 100644 index 06c8bab..0000000 --- a/ext/picotcp/RFC/rfc2474.txt +++ /dev/null @@ -1,1123 +0,0 @@ - - - - - - -Network Working Group K. Nichols -Request for Comments: 2474 Cisco Systems -Obsoletes: 1455, 1349 S. Blake -Category: Standards Track Torrent Networking Technologies - F. Baker - Cisco Systems - D. Black - EMC Corporation - December 1998 - - - Definition of the Differentiated Services Field (DS Field) - in the IPv4 and IPv6 Headers - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1998). All Rights Reserved. - -Abstract - - Differentiated services enhancements to the Internet protocol are - intended to enable scalable service discrimination in the Internet - without the need for per-flow state and signaling at every hop. A - variety of services may be built from a small, well-defined set of - building blocks which are deployed in network nodes. The services - may be either end-to-end or intra-domain; they include both those - that can satisfy quantitative performance requirements (e.g., peak - bandwidth) and those based on relative performance (e.g., "class" - differentiation). Services can be constructed by a combination of: - - - setting bits in an IP header field at network boundaries - (autonomous system boundaries, internal administrative boundaries, - or hosts), - - using those bits to determine how packets are forwarded by the - nodes inside the network, and - - conditioning the marked packets at network boundaries in accordance - with the requirements or rules of each service. - - - - - - -Nichols, et. al. Standards Track [Page 1] - -RFC 2474 Differentiated Services Field December 1998 - - - The requirements or rules of each service must be set through - administrative policy mechanisms which are outside the scope of this - document. A differentiated services-compliant network node includes - a classifier that selects packets based on the value of the DS field, - along with buffer management and packet scheduling mechanisms capable - of delivering the specific packet forwarding treatment indicated by - the DS field value. Setting of the DS field and conditioning of the - temporal behavior of marked packets need only be performed at network - boundaries and may vary in complexity. - - This document defines the IP header field, called the DS (for - differentiated services) field. In IPv4, it defines the layout of - the TOS octet; in IPv6, the Traffic Class octet. In addition, a base - set of packet forwarding treatments, or per-hop behaviors, is - defined. - - For a more complete understanding of differentiated services, see - also the differentiated services architecture [ARCH]. - -Table of Contents - - 1. Introduction ................................................. 3 - 2. Terminology Used in This Document ............................ 5 - 3. Differentiated Services Field Definition ..................... 7 - 4. Historical Codepoint Definitions and PHB Requirements ........ 9 - 4.1 A Default PHB ............................................. 9 - 4.2 Once and Future IP Precedence Field Use ................... 10 - 4.2.1 IP Precedence History and Evolution in Brief .......... 10 - 4.2.2 Subsuming IP Precedence into Class Selector .......... 11 - Codepoints - 4.2.2.1 The Class Selector Codepoints ..................... 11 - 4.2.2.2 The Class Selector PHB Requirements ............... 11 - 4.2.2.3 Using the Class Selector PHB Requirements ......... 12 - for IP Precedence Compatibility - 4.2.2.4 Example Mechanisms for Implementing Class ......... 12 - Selector Compliant PHB Groups - 4.3 Summary ................................................... 13 - 5. Per-Hop Behavior Standardization Guidelines .................. 13 - 6. IANA Considerations .......................................... 14 - 7. Security Considerations ...................................... 15 - 7.1 Theft and Denial of Service ............................... 15 - 7.2 IPsec and Tunneling Interactions .......................... 16 - 8. Acknowledgments .............................................. 17 - 9. References ................................................... 17 - Authors' Addresses ............................................... 19 - Full Copyright Statement ......................................... 20 - - - - - -Nichols, et. al. Standards Track [Page 2] - -RFC 2474 Differentiated Services Field December 1998 - - -1. Introduction - - Differentiated services are intended to provide a framework and - building blocks to enable deployment of scalable service - discrimination in the Internet. The differentiated services approach - aims to speed deployment by separating the architecture into two - major components, one of which is fairly well-understood and the - other of which is just beginning to be understood. In this, we are - guided by the original design of the Internet where the decision was - made to separate the forwarding and routing components. Packet - forwarding is the relatively simple task that needs to be performed - on a per-packet basis as quickly as possible. Forwarding uses the - packet header to find an entry in a routing table that determines the - packet's output interface. Routing sets the entries in that table - and may need to reflect a range of transit and other policies as well - as to keep track of route failures. Routing tables are maintained as - a background process to the forwarding task. Further, routing is the - more complex task and it has continued to evolve over the past 20 - years. - - Analogously, the differentiated services architecture contains two - main components. One is the fairly well-understood behavior in the - forwarding path and the other is the more complex and still emerging - background policy and allocation component that configures parameters - used in the forwarding path. The forwarding path behaviors include - the differential treatment an individual packet receives, as - implemented by queue service disciplines and/or queue management - disciplines. These per-hop behaviors are useful and required in - network nodes to deliver differentiated treatment of packets no - matter how we construct end-to-end or intra-domain services. Our - focus is on the general semantics of the behaviors rather than the - specific mechanisms used to implement them since these behaviors will - evolve less rapidly than the mechanisms. - - Per-hop behaviors and mechanisms to select them on a per-packet basis - can be deployed in network nodes today and it is this aspect of the - differentiated services architecture that is being addressed first. - In addition, the forwarding path may require that some monitoring, - policing, and shaping be done on the network traffic designated for - "special" treatment in order to enforce requirements associated with - the delivery of the special treatment. Mechanisms for this kind of - traffic conditioning are also fairly well-understood. The wide - deployment of such traffic conditioners is also important to enable - the construction of services, though their actual use in constructing - services may evolve over time. - - - - - - -Nichols, et. al. Standards Track [Page 3] - -RFC 2474 Differentiated Services Field December 1998 - - - The configuration of network elements with respect to which packets - get special treatment and what kinds of rules are to be applied to - the use of resources is much less well-understood. Nevertheless, it - is possible to deploy useful differentiated services in networks by - using simple policies and static configurations. As described in - [ARCH], there are a number of ways to compose per-hop behaviors and - traffic conditioners to create services. In the process, additional - experience is gained that will guide more complex policies and - allocations. The basic behaviors in the forwarding path can remain - the same while this component of the architecture evolves. - Experiences with the construction of such services will continue for - some time, thus we avoid standardizing this construction as it is - premature. Further, much of the details of service construction are - covered by legal agreements between different business entities and - we avoid this as it is very much outside the scope of the IETF. - - This document concentrates on the forwarding path component. In the - packet forwarding path, differentiated services are realized by - mapping the codepoint contained in a field in the IP packet header to - a particular forwarding treatment, or per-hop behavior (PHB), at each - network node along its path. The codepoints may be chosen from a set - of mandatory values defined later in this document, from a set of - recommended values to be defined in future documents, or may have - purely local meaning. PHBs are expected to be implemented by - employing a range of queue service and/or queue management - disciplines on a network node's output interface queue: for example - weighted round-robin (WRR) queue servicing or drop-preference queue - management. - - Marking is performed by traffic conditioners at network boundaries, - including the edges of the network (first-hop router or source host) - and administrative boundaries. Traffic conditioners may include the - primitives of marking, metering, policing and shaping (these - mechanisms are described in [ARCH]). Services are realized by the - use of particular packet classification and traffic conditioning - mechanisms at boundaries coupled with the concatenation of per-hop - behaviors along the transit path of the traffic. A goal of the - differentiated services architecture is to specify these building - blocks for future extensibility, both of the number and type of the - building blocks and of the services built from them. - - Terminology used in this memo is defined in Sec. 2. The - differentiated services field definition (DS field) is given in Sec. - 3. In Sec. 4, we discuss the desire for partial backwards - compatibility with current use of the IPv4 Precedence field. As a - solution, we introduce Class Selector Codepoints and Class Selector - - - - - -Nichols, et. al. Standards Track [Page 4] - -RFC 2474 Differentiated Services Field December 1998 - - - Compliant PHBs. Sec. 5 presents guidelines for per-hop behavior - standardization. Sec. 6 discusses guidelines for allocation of - codepoints. Sec. 7 covers security considerations. - - This document is a concise description of the DS field and its uses. - It is intended to be read along with the differentiated services - architecture [ARCH]. - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in [RFC2119]. - -2. Terminology Used in This Document - - Behavior Aggregate: a collection of packets with the same codepoint - crossing a link in a particular direction. The terms "aggregate" and - "behavior aggregate" are used interchangeably in this document. - - Classifier: an entity which selects packets based on the content of - packet headers according to defined rules. - - Class Selector Codepoint: any of the eight codepoints in the range ' - xxx000' (where 'x' may equal '0' or '1'). Class Selector Codepoints - are discussed in Sec. 4.2.2. - - Class Selector Compliant PHB: a per-hop behavior satisfying the Class - Selector PHB Requirements specified in Sec. 4.2.2.2. - - Codepoint: a specific value of the DSCP portion of the DS field. - Recommended codepoints SHOULD map to specific, standardized PHBs. - Multiple codepoints MAY map to the same PHB. - - Differentiated Services Boundary: the edge of a DS domain, where - classifiers and traffic conditioners are likely to be deployed. A - differentiated services boundary can be further sub-divided into - ingress and egress nodes, where the ingress/egress nodes are the - downstream/upstream nodes of a boundary link in a given traffic - direction. A differentiated services boundary typically is found at - the ingress to the first-hop differentiated services-compliant router - (or network node) that a host's packets traverse, or at the egress of - the last-hop differentiated services-compliant router or network node - that packets traverse before arriving at a host. This is sometimes - referred to as the boundary at a leaf router. A differentiated - services boundary may be co-located with a host, subject to local - policy. Also DS boundary. - - Differentiated Services-Compliant: in compliance with the - requirements specified in this document. Also DS-compliant. - - - -Nichols, et. al. Standards Track [Page 5] - -RFC 2474 Differentiated Services Field December 1998 - - - Differentiated Services Domain: a contiguous portion of the Internet - over which a consistent set of differentiated services policies are - administered in a coordinated fashion. A differentiated services - domain can represent different administrative domains or autonomous - systems, different trust regions, different network technologies - (e.g., cell/frame), hosts and routers, etc. Also DS domain. - - Differentiated Services Field: the IPv4 header TOS octet or the IPv6 - Traffic Class octet when interpreted in conformance with the - definition given in this document. Also DS field. - - Mechanism: The implementation of one or more per-hop behaviors - according to a particular algorithm. - - Microflow: a single instance of an application-to-application flow of - packets which is identified by source address, destination address, - protocol id, and source port, destination port (where applicable). - - Per-hop Behavior (PHB): a description of the externally observable - forwarding treatment applied at a differentiated services-compliant - node to a behavior aggregate. The description of a PHB SHOULD be - sufficiently detailed to allow the construction of predictable - services, as documented in [ARCH]. - - Per-hop Behavior Group: a set of one or more PHBs that can only be - meaningfully specified and implemented simultaneously, due to a - common constraint applying to all PHBs in the set such as a queue - servicing or queue management policy. Also PHB Group. - - Traffic Conditioning: control functions that can be applied to a - behavior aggregate, application flow, or other operationally useful - subset of traffic, e.g., routing updates. These MAY include - metering, policing, shaping, and packet marking. Traffic - conditioning is used to enforce agreements between domains and to - condition traffic to receive a differentiated service within a domain - by marking packets with the appropriate codepoint in the DS field and - by monitoring and altering the temporal characteristics of the - aggregate where necessary. See [ARCH]. - - Traffic Conditioner: an entity that performs traffic conditioning - functions and which MAY contain meters, policers, shapers, and - markers. Traffic conditioners are typically deployed in DS boundary - nodes (i.e., not in interior nodes of a DS domain). - - Service: a description of the overall treatment of (a subset of) a - customer's traffic across a particular domain, across a set of - interconnected DS domains, or end-to-end. Service descriptions are - covered by administrative policy and services are constructed by - - - -Nichols, et. al. Standards Track [Page 6] - -RFC 2474 Differentiated Services Field December 1998 - - - applying traffic conditioning to create behavior aggregates which - experience a known PHB at each node within the DS domain. Multiple - services can be supported by a single per-hop behavior used in - concert with a range of traffic conditioners. - - To summarize, classifiers and traffic conditioners are used to select - which packets are to be added to behavior aggregates. Aggregates - receive differentiated treatment in a DS domain and traffic - conditioners MAY alter the temporal characteristics of the aggregate - to conform to some requirements. A packet's DS field is used to - designate the packet's behavior aggregate and is subsequently used to - determine which forwarding treatment the packet receives. A behavior - aggregate classifier which can select a PHB, for example a - differential output queue servicing discipline, based on the - codepoint in the DS field SHOULD be included in all network nodes in - a DS domain. The classifiers and traffic conditioners at DS - boundaries are configured in accordance with some service - specification, a matter of administrative policy outside the scope of - this document. - - Additional differentiated services definitions are given in [ARCH]. - -3. Differentiated Services Field Definition - - A replacement header field, called the DS field, is defined, which is - intended to supersede the existing definitions of the IPv4 TOS octet - [RFC791] and the IPv6 Traffic Class octet [IPv6]. - - Six bits of the DS field are used as a codepoint (DSCP) to select the - PHB a packet experiences at each node. A two-bit currently unused - (CU) field is reserved and its definition and interpretation are - outside the scope of this document. The value of the CU bits are - ignored by differentiated services-compliant nodes when determining - the per-hop behavior to apply to a received packet. - - The DS field structure is presented below: - - - 0 1 2 3 4 5 6 7 - +---+---+---+---+---+---+---+---+ - | DSCP | CU | - +---+---+---+---+---+---+---+---+ - - DSCP: differentiated services codepoint - CU: currently unused - - - - - - -Nichols, et. al. Standards Track [Page 7] - -RFC 2474 Differentiated Services Field December 1998 - - - In a DSCP value notation 'xxxxxx' (where 'x' may equal '0' or '1') - used in this document, the left-most bit signifies bit 0 of the DS - field (as shown above), and the right-most bit signifies bit 5. - - Implementors should note that the DSCP field is six bits wide. DS- - compliant nodes MUST select PHBs by matching against the entire 6-bit - DSCP field, e.g., by treating the value of the field as a table index - which is used to select a particular packet handling mechanism which - has been implemented in that device. The value of the CU field MUST - be ignored by PHB selection. The DSCP field is defined as an - unstructured field to facilitate the definition of future per-hop - behaviors. - - With some exceptions noted below, the mapping of codepoints to PHBs - MUST be configurable. A DS-compliant node MUST support the logical - equivalent of a configurable mapping table from codepoints to PHBs. - PHB specifications MUST include a recommended default codepoint, - which MUST be unique for codepoints in the standard space (see Sec. - 6). Implementations should support the recommended codepoint-to-PHB - mappings in their default configuration. Operators may choose to use - different codepoints for a PHB, either in addition to or in place of - the recommended default. Note that if operators do so choose, re- - marking of DS fields may be necessary at administrative boundaries - even if the same PHBs are implemented on both sides of the boundary. - - See [ARCH] for further discussion of re-marking. - - The exceptions to general configurability are for codepoints 'xxx000' - and are noted in Secs. 4.2.2 and 4.3. - - Packets received with an unrecognized codepoint SHOULD be forwarded - as if they were marked for the Default behavior (see Sec. 4), and - their codepoints should not be changed. Such packets MUST NOT cause - the network node to malfunction. - - The structure of the DS field shown above is incompatible with the - existing definition of the IPv4 TOS octet in [RFC791]. The - presumption is that DS domains protect themselves by deploying re- - marking boundary nodes, as should networks using the RFC 791 - Precedence designations. Correct operational procedure SHOULD follow - [RFC791], which states: "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." Validating the value of the DS field - at DS boundaries is sensible in any case since an upstream node can - easily set it to any arbitrary value. DS domains that are not - isolated by suitably configured boundary nodes may deliver - unpredictable service. - - - -Nichols, et. al. Standards Track [Page 8] - -RFC 2474 Differentiated Services Field December 1998 - - - Nodes MAY rewrite the DS field as needed to provide a desired local - or end-to-end service. Specifications of DS field translations at DS - boundaries are the subject of service level agreements between - providers and users, and are outside the scope of this document. - Standardized PHBs allow providers to build their services from a - well-known set of packet forwarding treatments that can be expected - to be present in the equipment of many vendors. - -4. Historical Codepoint Definitions and PHB Requirements - - The DS field will have a limited backwards compatibility with current - practice, as described in this section. Backwards compatibility is - addressed in two ways. First, there are per-hop behaviors that are - already in widespread use (e.g., those satisfying the IPv4 Precedence - queueing requirements specified in [RFC1812]), and we wish to permit - their continued use in DS-compliant nodes. In addition, there are - some codepoints that correspond to historical use of the IP - Precedence field and we reserve these codepoints to map to PHBs that - meet the general requirements specified in Sec. 4.2.2.2, though the - specific differentiated services PHBs mapped to by those codepoints - MAY have additional specifications. - - No attempt is made to maintain backwards compatibility with the "DTR" - or TOS bits of the IPv4 TOS octet, as defined in [RFC791]. - -4.1 A Default PHB - - A "default" PHB MUST be available in a DS-compliant node. This is - the common, best-effort forwarding behavior available in existing - routers as standardized in [RFC1812]. When no other agreements are - in place, it is assumed that packets belong to this aggregate. Such - packets MAY be sent into a network without adhering to any particular - rules and the network will deliver as many of these packets as - possible and as soon as possible, subject to other resource policy - constraints. A reasonable implementation of this PHB would be a - queueing discipline that sends packets of this aggregate whenever the - output link is not required to satisfy another PHB. A reasonable - policy for constructing services would ensure that the aggregate was - not "starved". This could be enforced by a mechanism in each node - that reserves some minimal resources (e.g, buffers, bandwidth) for - Default behavior aggregates. This permits senders that are not - differentiated services-aware to continue to use the network in the - same manner as today. The impact of the introduction of - differentiated services into a domain on the service expectations of - its customers and peers is a complex matter involving policy - decisions by the domain and is outside the scope of this document. - The RECOMMENDED codepoint for the Default PHB is the bit pattern ' - 000000'; the value '000000' MUST map to a PHB that meets these - - - -Nichols, et. al. Standards Track [Page 9] - -RFC 2474 Differentiated Services Field December 1998 - - - specifications. The codepoint chosen for Default behavior is - compatible with existing practice [RFC791]. Where a codepoint is not - mapped to a standardized or local use PHB, it SHOULD be mapped to the - Default PHB. - - A packet initially marked for the Default behavior MAY be re-marked - with another codepoint as it passes a boundary into a DS domain so - that it will be forwarded using a different PHB within that domain, - possibly subject to some negotiated agreement between the peering - domains. - -4.2 Once and Future IP Precedence Field Use - - We wish to maintain some form of backward compatibility with present - uses of the IP Precedence Field: bits 0-2 of the IPv4 TOS octet. - Routers exist that use the IP Precedence field to select different - per-hop forwarding treatments in a similar way to the use proposed - here for the DSCP field. Thus, a simple prototype differentiated - services architecture can be quickly deployed by appropriately - configuring these routers. Further, IP systems today understand the - location of the IP Precedence field, and thus if these bits are used - in a similar manner as DS-compliant equipment is deployed, - significant failures are not likely during early deployment. In - other words, strict DS-compliance need not be ubiquitous even within - a single service provider's network if bits 0-2 of the DSCP field are - employed in a manner similar to, or subsuming, the deployed uses of - the IP Precedence field. - -4.2.1 IP Precedence History and Evolution in Brief - - The IP Precedence field is something of a forerunner of the DS field. - IP Precedence, and the IP Precedence Field, were first defined in - [RFC791]. The values that the three-bit IP Precedence Field might - take were assigned to various uses, including network control - traffic, routing traffic, and various levels of privilege. The least - level of privilege was deemed "routine traffic". In [RFC791], the - notion of Precedence was defined broadly as "An independent measure - of the importance of this datagram." Not all values of the IP - Precedence field were assumed to have meaning across boundaries, for - instance "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." [RFC791] - - Although early BBN IMPs implemented the Precedence feature, early - commercial routers and UNIX IP forwarding code generally did not. As - networks became more complex and customer requirements grew, - commercial router vendors developed ways to implement various kinds - of queueing services including priority queueing, which were - - - -Nichols, et. al. Standards Track [Page 10] - -RFC 2474 Differentiated Services Field December 1998 - - - generally based on policies encoded in filters in the routers, which - examined IP addresses, IP protocol numbers, TCP or UDP ports, and - other header fields. IP Precedence was and is among the options such - filters can examine. - - In short, IP Precedence is widely deployed and widely used, if not in - exactly the manner intended in [RFC791]. This was recognized in - [RFC1122], which states that while the use of the IP Precedence field - is valid, the specific assignment of the priorities in [RFC791] were - merely historical. - -4.2.2 Subsuming IP Precedence into Class Selector Codepoints - - A specification of the packet forwarding treatments selected by the - IP Precedence field today would have to be quite general; probably - not specific enough to build predictable services from in the - differentiated services framework. To preserve partial backwards - compatibility with known current uses of the IP Precedence field - without sacrificing future flexibility, we have taken the approach of - describing minimum requirements on a set of PHBs that are compatible - with most of the deployed forwarding treatments selected by the IP - Precedence field. In addition, we give a set of codepoints that MUST - map to PHBs meeting these minimum requirements. The PHBs mapped to - by these codepoints MAY have a more detailed list of specifications - in addition to the required ones stated here. Other codepoints MAY - map to these same PHBs. We refer to this set of codepoints as the - Class Selector Codepoints, and the minimum requirements for PHBs that - these codepoints may map to are called the Class Selector PHB - Requirements. - -4.2.2.1 The Class Selector Codepoints - - A specification of the packet forwarding treatments selected by the - The DS field values of 'xxx000|xx', or DSCP = 'xxx000' and CU - subfield unspecified, are reserved as a set of Class Selector - Codepoints. PHBs which are mapped to by these codepoints MUST - satisfy the Class Selector PHB requirements in addition to preserving - the Default PHB requirement on codepoint '000000' (Sec. 4.1). - -4.2.2.2 The Class Selector PHB Requirements - - We refer to a Class Selector Codepoint with a larger numerical value - than another Class Selector Codepoint as having a higher relative - order while a Class Selector Codepoint with a smaller numerical value - than another Class Selector Codepoint is said to have a lower - relative order. The set of PHBs mapped to by the eight Class - Selector Codepoints MUST yield at least two independently forwarded - classes of traffic, and PHBs selected by a Class Selector Codepoint - - - -Nichols, et. al. Standards Track [Page 11] - -RFC 2474 Differentiated Services Field December 1998 - - - SHOULD give packets a probability of timely forwarding that is not - lower than that given to packets marked with a Class Selector - codepoint of lower relative order, under reasonable operating - conditions and traffic loads. A discarded packet is considered to be - an extreme case of untimely forwarding. In addition, PHBs selected - by codepoints '11x000' MUST give packets a preferential forwarding - treatment by comparison to the PHB selected by codepoint '000000' to - preserve the common usage of IP Precedence values '110' and '111' for - routing traffic. - - Further, PHBs selected by distinct Class Selector Codepoints SHOULD - be independently forwarded; that is, packets marked with different - Class Selector Codepoints MAY be re-ordered. A network node MAY - enforce limits on the amount of the node's resources that can be - utilized by each of these PHBs. - - PHB groups whose specification satisfy these requirements are - referred to as Class Selector Compliant PHBs. - - The Class Selector PHB Requirements on codepoint '000000' are - compatible with those listed for the Default PHB in Sec. 4.1. - -4.2.2.3 Using the Class Selector PHB Requirements for IP Precedence - Compatibility - - A DS-compliant network node can be deployed with a set of one or more - Class Selector Compliant PHB groups. This document states that the - set of codepoints 'xxx000' MUST map to such a set of PHBs. As it is - also possible to map multiple codepoints to the same PHB, the vendor - or the network administrator MAY configure the network node to map - codepoints to PHBs irrespective of bits 3-5 of the DSCP field to - yield a network that is compatible with historical IP Precedence use. - Thus, for example, codepoint '011010' would map to the same PHB as - codepoint '011000'. - -4.2.2.4 Example Mechanisms for Implementing Class Selector Compliant - PHB Groups - - Class Selector Compliant PHBs can be realized by a variety of - mechanisms, including strict priority queueing, weighted fair - queueing (WFQ), WRR, or variants [RPS, HPFQA, DRR], or Class-Based - Queuing [CBQ]. The distinction between PHBs and mechanisms is - described in more detail in Sec. 5. - - It is important to note that these mechanisms might be available - through other PHBs (standardized or not) that are available in a - particular vendor's equipment. For example, future documents may - standardize a Strict Priority Queueing PHB group for a set of - - - -Nichols, et. al. Standards Track [Page 12] - -RFC 2474 Differentiated Services Field December 1998 - - - recommended codepoints. A network administrator might configure - those routers to select the Strict Priority Queueing PHBs with - codepoints 'xxx000' in conformance with the requirements of this - document. - - As a further example, another vendor might employ a CBQ mechanism in - its routers. The CBQ mechanism could be used to implement the Strict - Priority Queueing PHBs as well as a set of Class Selector Compliant - PHBs with a wider range of features than would be available in a set - of PHBs that did no more than meet the minimum Class Selector PHB - requirements. - -4.3 Summary - - This document defines codepoints 'xxx000' as the Class Selector - codepoints, where PHBs selected by these codepoints MUST meet the - Class Selector PHB Requirements described in Sec. 4.2.2.2. This is - done to preserve a useful level of backward compatibility with - current uses of the IP Precedence field in the Internet without - unduly limiting future flexibility. In addition, codepoint '000000' - is used as the Default PHB value for the Internet and, as such, is - not configurable. The remaining seven non-zero Class Selector - codepoints are configurable only to the extent that they map to PHBs - that meet the requirements in Sec. 4.2.2.2. - -5. Per-Hop Behavior Standardization Guidelines - - The behavioral characteristics of a PHB are to be standardized, and - not the particular algorithms or the mechanisms used to implement - them. A node may have a (possibly large) set of parameters that can - be used to control how packets are scheduled onto an output interface - (e.g., N separate queues with settable priorities, queue lengths, - round-robin weights, drop algorithm, drop preference weights and - thresholds, etc). To illustrate the distinction between a PHB and a - mechanism, we point out that Class Selector Compliant PHBs might be - implemented by several mechanisms, including: strict priority - queueing, WFQ, WRR, or variants [HPFQA, RPS, DRR], or CBQ [CBQ], in - isolation or in combination. - - PHBs may be specified individually, or as a group (a single PHB is a - special case of a PHB group). A PHB group usually consists of a set - of two or more PHBs that can only be meaningfully specified and - implemented simultaneously, due to a common constraint applying to - each PHB within the group, such as a queue servicing or queue - management policy. A PHB group specification SHOULD describe - conditions under which a packet might be re-marked to select another - PHB within the group. It is RECOMMENDED that PHB implementations do - not introduce any packet re-ordering within a microflow. PHB group - - - -Nichols, et. al. Standards Track [Page 13] - -RFC 2474 Differentiated Services Field December 1998 - - - specifications MUST identify any possible packet re-ordering - implications which may occur for each individual PHB, and which may - occur if different packets within a microflow are marked for - different PHBs within the group. - - Only those per-hop behaviors that are not described by an existing - PHB standard, and have been implemented, deployed, and shown to be - useful, SHOULD be standardized. Since current experience with - differentiated services is quite limited, it is premature to - hypothesize the exact specification of these per-hop behaviors. - - Each standardized PHB MUST have an associated RECOMMENDED codepoint, - allocated out of a space of 32 codepoints (see Sec. 6). This - specification has left room in the codepoint space to allow for - evolution, thus the defined space ('xxx000') is intentionally sparse. - - Network equipment vendors are free to offer whatever parameters and - capabilities are deemed useful or marketable. When a particular, - standardized PHB is implemented in a node, a vendor MAY use any - algorithm that satisfies the definition of the PHB according to the - standard. The node's capabilities and its particular configuration - determine the different ways that packets can be treated. - - Service providers are not required to use the same node mechanisms or - configurations to enable service differentiation within their - networks, and are free to configure the node parameters in whatever - way that is appropriate for their service offerings and traffic - engineering objectives. Over time certain common per-hop behaviors - are likely to evolve (i.e., ones that are particularly useful for - implementing end-to-end services) and these MAY be associated with - particular EXP/LU PHB codepoints in the DS field, allowing use across - domain boundaries (see Sec. 6). These PHBs are candidates for future - standardization. - - It is RECOMMENDED that standardized PHBs be specified in accordance - with the guidelines set out in [ARCH]. - -6. IANA Considerations - - The DSCP field within the DS field is capable of conveying 64 - distinct codepoints. The codepoint space is divided into three pools - for the purpose of codepoint assignment and management: a pool of 32 - RECOMMENDED codepoints (Pool 1) to be assigned by Standards Action as - defined in [CONS], a pool of 16 codepoints (Pool 2) to be reserved - for experimental or Local Use (EXP/LU) as defined in [CONS], and a - pool of 16 codepoints (Pool 3) which are initially available for - experimental or local use, but which should be preferentially - - - - -Nichols, et. al. Standards Track [Page 14] - -RFC 2474 Differentiated Services Field December 1998 - - - utilized for standardized assignments if Pool 1 is ever exhausted. - The pools are defined in the following table (where 'x' refers to - either '0' or '1'): - - Pool Codepoint space Assignment Policy - ---- --------------- ----------------- - - 1 xxxxx0 Standards Action - 2 xxxx11 EXP/LU - 3 xxxx01 EXP/LU (*) - - (*) may be utilized for future Standards Action allocations as - necessary - - This document assigns eight RECOMMENDED codepoints ('xxx000') which - are drawn from Pool 1 above. These codepoints MUST be mapped, not to - specific PHBs, but to PHBs that meet "at least" the requirements set - forth in Sec. 4.2.2.2 to provide a minimal level of backwards - compatibility with IP Precedence as defined in [RFC791] and as - deployed in some current equipment. - -7. Security Considerations - - This section considers security issues raised by the introduction of - differentiated services, primarily the potential for denial-of- - service attacks, and the related potential for theft of service by - unauthorized traffic (Section 7.1). Section 7.2 addresses the - operation of differentiated services in the presence of IPsec - including its interaction with IPsec tunnel mode and other tunnelling - protocols. See [ARCH] for more extensive treatment of the security - concerns raised by the overall differentiated services architecture. - -7.1 Theft and Denial of Service - - The primary goal of differentiated services is to allow different - levels of service to be provided for traffic streams on a common - network infrastructure. A variety of techniques may be used to - achieve this, but the end result will be that some packets receive - different (e.g., better) service than others. The mapping of network - traffic to the specific behaviors that result in different (e.g., - better or worse) service is indicated primarily by the DS codepoint, - and hence an adversary may be able to obtain better service by - modifying the codepoint to values indicating behaviors used for - enhanced services or by injecting packets with such codepoint values. - Taken to its limits, such theft-of-service becomes a denial-of- - service attack when the modified or injected traffic depletes the - resources available to forward it and other traffic streams. - - - - -Nichols, et. al. Standards Track [Page 15] - -RFC 2474 Differentiated Services Field December 1998 - - - The defense against this class of theft- and denial-of-service - attacks consists of the combination of traffic conditioning at DS - domain boundaries with security and integrity of the network - infrastructure within a DS domain. DS domain boundary nodes MUST - ensure that all traffic entering the domain is marked with codepoint - values appropriate to the traffic and the domain, remarking the - traffic with new codepoint values if necessary. These DS boundary - nodes are the primary line of defense against theft- and denial-of- - service attacks based on modified codepoints, as success of any such - attack indicates that the codepoints used by the attacking traffic - were inappropriate. An important instance of a boundary node is that - any traffic-originating node within a DS domain is the initial - boundary node for that traffic. Interior nodes in a DS domain rely - on DS codepoints to associate traffic with the forwarding PHBs, and - are NOT REQUIRED to check codepoint values before using them. As a - result, the interior nodes depend on the correct operation of the DS - domain boundary nodes to prevent the arrival of traffic with - inappropriate codepoints or in excess of provisioned levels that - would disrupt operation of the domain. - -7.2 IPsec and Tunnelling Interactions - - The IPsec protocol, as defined in [ESP, AH], does not include the IP - header's DS field in any of its cryptographic calculations (in the - case of tunnel mode, it is the outer IP header's DS field that is not - included). Hence modification of the DS field by a network node has - no effect on IPsec's end-to-end security, because it cannot cause any - IPsec integrity check to fail. As a consequence, IPsec does not - provide any defense against an adversary's modification of the DS - field (i.e., a man-in-the-middle attack), as the adversary's - modification will also have no effect on IPsec's end-to-end security. - - IPsec's tunnel mode provides security for the encapsulated IP - header's DS field. A tunnel mode IPsec packet contains two IP - headers: an outer header supplied by the tunnel ingress node and an - encapsulated inner header supplied by the original source of the - packet. When an IPsec tunnel is hosted (in whole or in part) on a - differentiated services network, the intermediate network nodes - operate on the DS field in the outer header. At the tunnel egress - node, IPsec processing includes removing the outer header and - forwarding the packet (if required) using the inner header. The - IPsec protocol REQUIRES that the inner header's DS field not be - changed by this decapsulation processing to ensure that modifications - to the DS field cannot be used to launch theft- or denial-of-service - attacks across an IPsec tunnel endpoint. This document makes no - change to that requirement. If the inner IP header has not been - processed by a DS boundary node for the tunnel egress node's DS - - - - -Nichols, et. al. Standards Track [Page 16] - -RFC 2474 Differentiated Services Field December 1998 - - - domain, the tunnel egress node is the boundary node for traffic - exiting the tunnel, and hence MUST ensure that the resulting traffic - has appropriate DS codepoints. - - When IPsec tunnel egress decapsulation processing includes a - sufficiently strong cryptographic integrity check of the encapsulated - packet (where sufficiency is determined by local security policy), - the tunnel egress node can safely assume that the DS field in the - inner header has the same value as it had at the tunnel ingress node. - An important consequence is that otherwise insecure links within a DS - domain can be secured by a sufficiently strong IPsec tunnel. This - analysis and its implications apply to any tunnelling protocol that - performs integrity checks, but the level of assurance of the inner - header's DS field depends on the strength of the integrity check - performed by the tunnelling protocol. In the absence of sufficient - assurance for a tunnel that may transit nodes outside the current DS - domain (or is otherwise vulnerable), the encapsulated packet MUST be - treated as if it had arrived at a boundary from outside the DS - domain. - -8. Acknowledgements - - The authors would like to acknowledge the Differentiated Services - Working Group for discussions which helped shape this document. - -9. References - - [AH] Kent, S. and R. Atkinson, "IP Authentication Header", - RFC 2402, November 1998. - - [ARCH] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z. - and W. Weiss, "An Architecture for Differentiated - Services", RFC 2475, December 1998. - - [CBQ] S. Floyd and V. Jacobson, "Link-sharing and Resource - Management Models for Packet Networks", IEEE/ACM - Transactions on Networking, Vol. 3 no. 4, pp. 365-386, - August 1995. - - [CONS] Narten, T. and H. Alvestrand, "Guidelines for Writing an - IANA Considerations Section in RFCs", RFC 2434, October - 1998. - - [DRR] M. Shreedhar and G. Varghese, Efficient Fair Queueing - using Deficit Round Robin", Proc. ACM SIGCOMM 95, 1995. - - - - - - -Nichols, et. al. Standards Track [Page 17] - -RFC 2474 Differentiated Services Field December 1998 - - - [ESP] Kent, S. and R. Atkinson, "IP Encapsulating Security - Payload (ESP)", RFC 2406, November 1998. - - [HPFQA] J. Bennett and Hui Zhang, "Hierarchical Packet Fair - Queueing Algorithms", Proc. ACM SIGCOMM 96, August 1996. - - [IPv6] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC791] Postel, J., Editor, "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC1122] Braden, R., "Requirements for Internet hosts - - communication layers", STD 3, RFC 1122, October 1989. - - [RFC1812] Baker, F., Editor, "Requirements for IP Version 4 - Routers", RFC 1812, June 1995. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RPS] D. Stiliadis and A. Varma, "Rate-Proportional Servers: A - Design Methodology for Fair Queueing Algorithms", IEEE/ - ACM Trans. on Networking, April 1998. - - - - - - - - - - - - - - - - - - - - - - - - - - - -Nichols, et. al. Standards Track [Page 18] - -RFC 2474 Differentiated Services Field December 1998 - - -Authors' Addresses - - Kathleen Nichols - Cisco Systems - 170 West Tasman Drive - San Jose, CA 95134-1706 - - Phone: +1-408-525-4857 - EMail: kmn@cisco.com - - - Steven Blake - Torrent Networking Technologies - 3000 Aerial Center, Suite 140 - Morrisville, NC 27560 - - Phone: +1-919-468-8466 x232 - EMail: slblake@torrentnet.com - - - Fred Baker - Cisco Systems - 519 Lado Drive - Santa Barbara, CA 93111 - - Phone: +1-408-526-4257 - EMail: fred@cisco.com - - - David L. Black - EMC Corporation - 35 Parkwood Drive - Hopkinton, MA 01748 - - Phone: +1-508-435-1000 x76140 - EMail: black_david@emc.com - - - - - - - - - - - - - - - -Nichols, et. al. Standards Track [Page 19] - -RFC 2474 Differentiated Services Field December 1998 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1998). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Nichols, et. al. Standards Track [Page 20] - diff --git a/ext/picotcp/RFC/rfc2488.txt b/ext/picotcp/RFC/rfc2488.txt deleted file mode 100644 index 7fa5700..0000000 --- a/ext/picotcp/RFC/rfc2488.txt +++ /dev/null @@ -1,1067 +0,0 @@ - - - - - - -Network Working Group M. Allman -Request for Comments: 2488 NASA Lewis/Sterling Software -BCP: 28 D. Glover -Category: Best Current Practice NASA Lewis - L. Sanchez - BBN - January 1999 - - Enhancing TCP Over Satellite Channels - using Standard Mechanisms - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1999). All Rights Reserved. - -Abstract - - The Transmission Control Protocol (TCP) provides reliable delivery of - data across any network path, including network paths containing - satellite channels. While TCP works over satellite channels there - are several IETF standardized mechanisms that enable TCP to more - effectively utilize the available capacity of the network path. This - document outlines some of these TCP mitigations. At this time, all - mitigations discussed in this document are IETF standards track - mechanisms (or are compliant with IETF standards). - -1. Introduction - - Satellite channel characteristics may have an effect on the way - transport protocols, such as the Transmission Control Protocol (TCP) - [Pos81], behave. When protocols, such as TCP, perform poorly, - channel utilization is low. While the performance of a transport - protocol is important, it is not the only consideration when - constructing a network containing satellite links. For example, data - link protocol, application protocol, router buffer size, queueing - discipline and proxy location are some of the considerations that - must be taken into account. However, this document focuses on - improving TCP in the satellite environment and non-TCP considerations - are left for another document. Finally, there have been many - satellite mitigations proposed and studied by the research community. - While these mitigations may prove useful and safe for shared networks - in the future, this document only considers TCP mechanisms which are - - - -Allman, et. al. Best Current Practice [Page 1] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - currently well understood and on the IETF standards track (or are - compliant with IETF standards). - - This document is divided up as follows: Section 2 provides a brief - outline of the characteristics of satellite networks. Section 3 - outlines two non-TCP mechanisms that enable TCP to more effectively - utilize the available bandwidth. Section 4 outlines the TCP - mechanisms defined by the IETF that may benefit satellite networks. - Finally, Section 5 provides a summary of what modern TCP - implementations should include to be considered "satellite friendly". - -2. Satellite Characteristics - - There is an inherent delay in the delivery of a message over a - satellite link due to the finite speed of light and the altitude of - communications satellites. - - Many communications satellites are located at Geostationary Orbit - (GSO) with an altitude of approximately 36,000 km [Sta94]. At this - altitude the orbit period is the same as the Earth's rotation period. - Therefore, each ground station is always able to "see" the orbiting - satellite at the same position in the sky. The propagation time for - a radio signal to travel twice that distance (corresponding to a - ground station directly below the satellite) is 239.6 milliseconds - (ms) [Mar78]. For ground stations at the edge of the view area of - the satellite, the distance traveled is 2 x 41,756 km for a total - propagation delay of 279.0 ms [Mar78]. These delays are for one - ground station-to-satellite-to-ground station route (or "hop"). - Therefore, the propagation delay for a message and the corresponding - reply (one round-trip time or RTT) could be at least 558 ms. The RTT - is not based solely on satellite propagation time. The RTT will be - increased by other factors in the network, such as the transmission - time and propagation time of other links in the network path and - queueing delay in gateways. Furthermore, the satellite propagation - delay will be longer if the link includes multiple hops or if - intersatellite links are used. As satellites become more complex and - include on-board processing of signals, additional delay may be - added. - - Other orbits are possible for use by communications satellites - including Low Earth Orbit (LEO) [Stu95] [Mon98] and Medium Earth - Orbit (MEO) [Mar78]. The lower orbits require the use of - constellations of satellites for constant coverage. In other words, - as one satellite leaves the ground station's sight, another satellite - appears on the horizon and the channel is switched to it. The - propagation delay to a LEO orbit ranges from several milliseconds - when communicating with a satellite directly overhead, to as much as - 80 ms when the satellite is on the horizon. These systems are more - - - -Allman, et. al. Best Current Practice [Page 2] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - likely to use intersatellite links and have variable path delay - depending on routing through the network. - - Satellite channels are dominated by two fundamental characteristics, - as described below: - - NOISE - The strength of a radio signal falls in proportion to the - square of the distance traveled. For a satellite link the - distance is large and so the signal becomes weak before reaching - its destination. This results in a low signal-to-noise ratio. - Some frequencies are particularly susceptible to atmospheric - effects such as rain attenuation. For mobile applications, - satellite channels are especially susceptible to multi-path - distortion and shadowing (e.g., blockage by buildings). Typical - bit error rates (BER) for a satellite link today are on the order - of 1 error per 10 million bits (1 x 10^-7) or less frequent. - Advanced error control coding (e.g., Reed Solomon) can be added to - existing satellite services and is currently being used by many - services. Satellite error performance approaching fiber will - become more common as advanced error control coding is used in new - systems. However, many legacy satellite systems will continue to - exhibit higher BER than newer satellite systems and terrestrial - channels. - - BANDWIDTH - The radio spectrum is a limited natural resource, - hence there is a restricted amount of bandwidth available to - satellite systems which is typically controlled by licenses. This - scarcity makes it difficult to trade bandwidth to solve other - design problems. Typical carrier frequencies for current, point- - to-point, commercial, satellite services are 6 GHz (uplink) and 4 - GHz (downlink), also known as C band, and 14/12 GHz (Ku band). A - new service at 30/20 GHz (Ka band) will be emerging over the next - few years. Satellite-based radio repeaters are known as - transponders. Traditional C band transponder bandwidth is - typically 36 MHz to accommodate one color television channel (or - 1200 voice channels). Ku band transponders are typically around - 50 MHz. Furthermore, one satellite may carry a few dozen - transponders. - - Not only is bandwidth limited by nature, but the allocations for - commercial communications are limited by international agreements so - that this scarce resource can be used fairly by many different - applications. - - - - - - - - -Allman, et. al. Best Current Practice [Page 3] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - Although satellites have certain disadvantages when compared to fiber - channels (e.g., cannot be easily repaired, rain fades, etc.), they - also have certain advantages over terrestrial links. First, - satellites have a natural broadcast capability. This gives - satellites an advantage for multicast applications. Next, satellites - can reach geographically remote areas or countries that have little - terrestrial infrastructure. A related advantage is the ability of - satellite links to reach mobile users. - - Satellite channels have several characteristics that differ from most - terrestrial channels. These characteristics may degrade the - performance of TCP. These characteristics include: - - Long feedback loop - - Due to the propagation delay of some satellite channels (e.g., - approximately 250 ms over a geosynchronous satellite) it may take - a long time for a TCP sender to determine whether or not a packet - has been successfully received at the final destination. This - delay hurts interactive applications such as telnet, as well as - some of the TCP congestion control algorithms (see section 4). - - Large delay*bandwidth product - - The delay*bandwidth product (DBP) defines the amount of data a - protocol should have "in flight" (data that has been transmitted, - but not yet acknowledged) at any one time to fully utilize the - available channel capacity. The delay used in this equation is - the RTT and the bandwidth is the capacity of the bottleneck link - in the network path. Because the delay in some satellite - environments is large, TCP will need to keep a large number of - packets "in flight" (that is, sent but not yet acknowledged) . - - Transmission errors - - Satellite channels exhibit a higher bit-error rate (BER) than - typical terrestrial networks. TCP uses all packet drops as - signals of network congestion and reduces its window size in an - attempt to alleviate the congestion. In the absence of knowledge - about why a packet was dropped (congestion or corruption), TCP - must assume the drop was due to network congestion to avoid - congestion collapse [Jac88] [FF98]. Therefore, packets dropped - due to corruption cause TCP to reduce the size of its sliding - window, even though these packet drops do not signal congestion in - the network. - - - - - - -Allman, et. al. Best Current Practice [Page 4] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - Asymmetric use - - Due to the expense of the equipment used to send data to - satellites, asymmetric satellite networks are often constructed. - For example, a host connected to a satellite network will send all - outgoing traffic over a slow terrestrial link (such as a dialup - modem channel) and receive incoming traffic via the satellite - channel. Another common situation arises when both the incoming - and outgoing traffic are sent using a satellite link, but the - uplink has less available capacity than the downlink due to the - expense of the transmitter required to provide a high bandwidth - back channel. This asymmetry may have an impact on TCP - performance. - - Variable Round Trip Times - - In some satellite environments, such as low-Earth orbit (LEO) - constellations, the propagation delay to and from the satellite - varies over time. Whether or not this will have an impact on TCP - performance is currently an open question. - - Intermittent connectivity - - In non-GSO satellite orbit configurations, TCP connections must be - transferred from one satellite to another or from one ground - station to another from time to time. This handoff may cause - packet loss if not properly performed. - - Most satellite channels only exhibit a subset of the above - characteristics. Furthermore, satellite networks are not the only - environments where the above characteristics are found. However, - satellite networks do tend to exhibit more of the above problems or - the above problems are aggravated in the satellite environment. The - mechanisms outlined in this document should benefit most networks, - especially those with one or more of the above characteristics (e.g., - gigabit networks have large delay*bandwidth products). - -3. Lower Level Mitigations - - It is recommended that those utilizing satellite channels in their - networks should use the following two non-TCP mechanisms which can - increase TCP performance. These mechanisms are Path MTU Discovery - and forward error correction (FEC) and are outlined in the following - two sections. - - The data link layer protocol employed over a satellite channel can - have a large impact on performance of higher layer protocols. While - beyond the scope of this document, those constructing satellite - - - -Allman, et. al. Best Current Practice [Page 5] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - networks should tune these protocols in an appropriate manner to - ensure that the data link protocol does not limit TCP performance. - In particular, data link layer protocols often implement a flow - control window and retransmission mechanisms. When the link level - window size is too small, performance will suffer just as when the - TCP window size is too small (see section 4.3 for a discussion of - appropriate window sizes). The impact that link level - retransmissions have on TCP transfers is not currently well - understood. The interaction between TCP retransmissions and link - level retransmissions is a subject for further research. - -3.1 Path MTU Discovery - - Path MTU discovery [MD90] is used to determine the maximum packet - size a connection can use on a given network path without being - subjected to IP fragmentation. The sender transmits a packet that is - the appropriate size for the local network to which it is connected - (e.g., 1500 bytes on an Ethernet) and sets the IP "don't fragment" - (DF) bit. If the packet is too large to be forwarded without being - fragmented to a given channel along the network path, the gateway - that would normally fragment the packet and forward the fragments - will instead return an ICMP message to the originator of the packet. - The ICMP message will indicate that the original segment could not be - transmitted without being fragmented and will also contain the size - of the largest packet that can be forwarded by the gateway. - Additional information from the IESG regarding Path MTU discovery is - available in [Kno93]. - - Path MTU Discovery allows TCP to use the largest possible packet - size, without incurring the cost of fragmentation and reassembly. - Large packets reduce the packet overhead by sending more data bytes - per overhead byte. As outlined in section 4, increasing TCP's - congestion window is segment based, rather than byte based and - therefore, larger segments enable TCP senders to increase the - congestion window more rapidly, in terms of bytes, than smaller - segments. - - The disadvantage of Path MTU Discovery is that it may cause a delay - before TCP is able to start sending data. For example, assume a - packet is sent with the DF bit set and one of the intervening - gateways (G1) returns an ICMP message indicating that it cannot - forward the segment. At this point, the sending host reduces the - packet size per the ICMP message returned by G1 and sends another - packet with the DF bit set. The packet will be forwarded by G1, - however this does not ensure all subsequent gateways in the network - path will be able to forward the segment. If a second gateway (G2) - cannot forward the segment it will return an ICMP message to the - transmitting host and the process will be repeated. Therefore, path - - - -Allman, et. al. Best Current Practice [Page 6] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - MTU discovery can spend a large amount of time determining the - maximum allowable packet size on the network path between the sender - and receiver. Satellite delays can aggravate this problem (consider - the case when the channel between G1 and G2 is a satellite link). - However, in practice, Path MTU Discovery does not consume a large - amount of time due to wide support of common MTU values. - Additionally, caching MTU values may be able to eliminate discovery - time in many instances, although the exact implementation of this and - the aging of cached values remains an open problem. - - The relationship between BER and segment size is likely to vary - depending on the error characteristics of the given channel. This - relationship deserves further study, however with the use of good - forward error correction (see section 3.2) larger segments should - provide better performance, as with any network [MSMO97]. While the - exact method for choosing the best MTU for a satellite link is - outside the scope of this document, the use of Path MTU Discovery is - recommended to allow TCP to use the largest possible MTU over the - satellite channel. - -3.2 Forward Error Correction - - A loss event in TCP is always interpreted as an indication of - congestion and always causes TCP to reduce its congestion window - size. Since the congestion window grows based on returning - acknowledgments (see section 4), TCP spends a long time recovering - from loss when operating in satellite networks. When packet loss is - due to corruption, rather than congestion, TCP does not need to - reduce its congestion window size. However, at the present time - detecting corruption loss is a research issue. - - Therefore, for TCP to operate efficiently, the channel - characteristics should be such that nearly all loss is due to network - congestion. The use of forward error correction coding (FEC) on a - satellite link should be used to improve the bit-error rate (BER) of - the satellite channel. Reducing the BER is not always possible in - satellite environments. However, since TCP takes a long time to - recover from lost packets because the long propagation delay imposed - by a satellite link delays feedback from the receiver [PS97], the - link should be made as clean as possible to prevent TCP connections - from receiving false congestion signals. This document does not make - a specific BER recommendation for TCP other than it should be as low - as possible. - - FEC should not be expected to fix all problems associated with noisy - satellite links. There are some situations where FEC cannot be - expected to solve the noise problem (such as military jamming, deep - space missions, noise caused by rain fade, etc.). In addition, link - - - -Allman, et. al. Best Current Practice [Page 7] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - outages can also cause problems in satellite systems that do not - occur as frequently in terrestrial networks. Finally, FEC is not - without cost. FEC requires additional hardware and uses some of the - available bandwidth. It can add delay and timing jitter due to the - processing time of the coder/decoder. - - Further research is needed into mechanisms that allow TCP to - differentiate between congestion induced drops and those caused by - corruption. Such a mechanism would allow TCP to respond to - congestion in an appropriate manner, as well as repairing corruption - induced loss without reducing the transmission rate. However, in the - absence of such a mechanism packet loss must be assumed to indicate - congestion to preserve network stability. Incorrectly interpreting - loss as caused by corruption and not reducing the transmission rate - accordingly can lead to congestive collapse [Jac88] [FF98]. - -4. Standard TCP Mechanisms - - This section outlines TCP mechanisms that may be necessary in - satellite or hybrid satellite/terrestrial networks to better utilize - the available capacity of the link. These mechanisms may also be - needed to fully utilize fast terrestrial channels. Furthermore, - these mechanisms do not fundamentally hurt performance in a shared - terrestrial network. Each of the following sections outlines one - mechanism and why that mechanism may be needed. - -4.1 Congestion Control - - To avoid generating an inappropriate amount of network traffic for - the current network conditions, during a connection TCP employs four - congestion control mechanisms [Jac88] [Jac90] [Ste97]. These - algorithms are slow start, congestion avoidance, fast retransmit and - fast recovery. These algorithms are used to adjust the amount of - unacknowledged data that can be injected into the network and to - retransmit segments dropped by the network. - - TCP senders use two state variables to accomplish congestion control. - The first variable is the congestion window (cwnd). This is an upper - bound on the amount of data the sender can inject into the network - before receiving an acknowledgment (ACK). The value of cwnd is - limited to the receiver's advertised window. The congestion window - is increased or decreased during the transfer based on the inferred - amount of congestion present in the network. The second variable is - the slow start threshold (ssthresh). This variable determines which - algorithm is used to increase the value of cwnd. If cwnd is less - than ssthresh the slow start algorithm is used to increase the value - of cwnd. However, if cwnd is greater than or equal to (or just - greater than in some TCP implementations) ssthresh the congestion - - - -Allman, et. al. Best Current Practice [Page 8] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - avoidance algorithm is used. The initial value of ssthresh is the - receiver's advertised window size. Furthermore, the value of - ssthresh is set when congestion is detected. - - The four congestion control algorithms are outlined below, followed - by a brief discussion of the impact of satellite environments on - these algorithms. - -4.1.1 Slow Start and Congestion Avoidance - - When a host begins sending data on a TCP connection the host has no - knowledge of the current state of the network between itself and the - data receiver. In order to avoid transmitting an inappropriately - large burst of traffic, the data sender is required to use the slow - start algorithm at the beginning of a transfer [Jac88] [Bra89] - [Ste97]. Slow start begins by initializing cwnd to 1 segment - (although an IETF experimental mechanism would increase the size of - the initial window to roughly 4 Kbytes [AFP98]) and ssthresh to the - receiver's advertised window. This forces TCP to transmit one - segment and wait for the corresponding ACK. For each ACK that is - received during slow start, the value of cwnd is increased by 1 - segment. For example, after the first ACK is received cwnd will be 2 - segments and the sender will be allowed to transmit 2 data packets. - This continues until cwnd meets or exceeds ssthresh (or, in some - implementations when cwnd equals ssthresh), or loss is detected. - - When the value of cwnd is greater than or equal to (or equal to in - certain implementations) ssthresh the congestion avoidance algorithm - is used to increase cwnd [Jac88] [Bra89] [Ste97]. This algorithm - increases the size of cwnd more slowly than does slow start. - Congestion avoidance is used to slowly probe the network for - additional capacity. During congestion avoidance, cwnd is increased - by 1/cwnd for each incoming ACK. Therefore, if one ACK is received - for every data segment, cwnd will increase by roughly 1 segment per - round-trip time (RTT). - - The slow start and congestion control algorithms can force poor - utilization of the available channel bandwidth when using long-delay - satellite networks [All97]. For example, transmission begins with - the transmission of one segment. After the first segment is - transmitted the data sender is forced to wait for the corresponding - ACK. When using a GSO satellite this leads to an idle time of - roughly 500 ms when no useful work is being accomplished. Therefore, - slow start takes more real time over GSO satellites than on typical - terrestrial channels. This holds for congestion avoidance, as well - [All97]. This is precisely why Path MTU Discovery is an important - algorithm. While the number of segments we transmit is determined by - the congestion control algorithms, the size of these segments is not. - - - -Allman, et. al. Best Current Practice [Page 9] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - Therefore, using larger packets will enable TCP to send more data per - segment which yields better channel utilization. - -4.1.2 Fast Retransmit and Fast Recovery - - TCP's default mechanism to detect dropped segments is a timeout - [Pos81]. In other words, if the sender does not receive an ACK for a - given packet within the expected amount of time the segment will be - retransmitted. The retransmission timeout (RTO) is based on - observations of the RTT. In addition to retransmitting a segment - when the RTO expires, TCP also uses the lost segment as an indication - of congestion in the network. In response to the congestion, the - value of ssthresh is set to half of the cwnd and the value of cwnd is - then reduced to 1 segment. This triggers the use of the slow start - algorithm to increase cwnd until the value of cwnd reaches half of - its value when congestion was detected. After the slow start phase, - the congestion avoidance algorithm is used to probe the network for - additional capacity. - - TCP ACKs always acknowledge the highest in-order segment that has - arrived. Therefore an ACK for segment X also effectively ACKs all - segments < X. Furthermore, if a segment arrives out-of-order the ACK - triggered will be for the highest in-order segment, rather than the - segment that just arrived. For example, assume segment 11 has been - dropped somewhere in the network and segment 12 arrives at the - receiver. The receiver is going to send a duplicate ACK covering - segment 10 (and all previous segments). - - The fast retransmit algorithm uses these duplicate ACKs to detect - lost segments. If 3 duplicate ACKs arrive at the data originator, - TCP assumes that a segment has been lost and retransmits the missing - segment without waiting for the RTO to expire. After a segment is - resent using fast retransmit, the fast recovery algorithm is used to - adjust the congestion window. First, the value of ssthresh is set to - half of the value of cwnd. Next, the value of cwnd is halved. - Finally, the value of cwnd is artificially increased by 1 segment for - each duplicate ACK that has arrived. The artificial inflation can be - done because each duplicate ACK represents 1 segment that has left - the network. When the cwnd permits, TCP is able to transmit new - data. This allows TCP to keep data flowing through the network at - half the rate it was when loss was detected. When an ACK for the - retransmitted packet arrives, the value of cwnd is reduced back to - ssthresh (half the value of cwnd when the congestion was detected). - - - - - - - - -Allman, et. al. Best Current Practice [Page 10] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - Generally, fast retransmit can resend only one segment per window of - data sent. When multiple segments are lost in a given window of - data, one of the segments will be resent using fast retransmit and - the rest of the dropped segments must usually wait for the RTO to - expire, which causes TCP to revert to slow start. - - TCP's response to congestion differs based on the way the congestion - is detected. If the retransmission timer causes a packet to be - resent, TCP drops ssthresh to half the current cwnd and reduces the - value of cwnd to 1 segment (thus triggering slow start). However, if - a segment is resent via fast retransmit both ssthresh and cwnd are - set to half the current value of cwnd and congestion avoidance is - used to send new data. The difference is that when retransmitting - due to duplicate ACKs, TCP knows that packets are still flowing - through the network and can therefore infer that the congestion is - not that bad. However, when resending a packet due to the expiration - of the retransmission timer, TCP cannot infer anything about the - state of the network and therefore must proceed conservatively by - sending new data using the slow start algorithm. - - Note that the fast retransmit/fast recovery algorithms, as discussed - above can lead to a phenomenon that allows multiple fast retransmits - per window of data [Flo94]. This can reduce the size of the - congestion window multiple times in response to a single "loss - event". The problem is particularly noticeable in connections that - utilize large congestion windows, since these connections are able to - inject enough new segments into the network during recovery to - trigger the multiple fast retransmits. Reducing cwnd multiple times - for a single loss event may hurt performance [GJKFV98]. - - The best way to improve the fast retransmit/fast recovery algorithms - is to use a selective acknowledgment (SACK) based algorithm for loss - recovery. As discussed below, these algorithms are generally able to - quickly recover from multiple lost segments without needlessly - reducing the value of cwnd. In the absence of SACKs, the fast - retransmit and fast recovery algorithms should be used. Fixing these - algorithms to achieve better performance in the face of multiple fast - retransmissions is beyond the scope of this document. Therefore, TCP - implementers are advised to implement the current version of fast - retransmit/fast recovery outlined in RFC 2001 [Ste97] or subsequent - versions of RFC 2001. - -4.1.3 Congestion Control in Satellite Environment - - The above algorithms have a negative impact on the performance of - individual TCP connection's performance because the algorithms slowly - probe the network for additional capacity, which in turn wastes - bandwidth. This is especially true over long-delay satellite - - - -Allman, et. al. Best Current Practice [Page 11] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - channels because of the large amount of time required for the sender - to obtain feedback from the receiver [All97] [AHKO97]. However, the - algorithms are necessary to prevent congestive collapse in a shared - network [Jac88]. Therefore, the negative impact on a given - connection is more than offset by the benefit to the entire network. - -4.2 Large TCP Windows - - The standard maximum TCP window size (65,535 bytes) is not adequate - to allow a single TCP connection to utilize the entire bandwidth - available on some satellite channels. TCP throughput is limited by - the following formula [Pos81]: - - throughput = window size / RTT - - Therefore, using the maximum window size of 65,535 bytes and a - geosynchronous satellite channel RTT of 560 ms [Kru95] the maximum - throughput is limited to: - - throughput = 65,535 bytes / 560 ms = 117,027 bytes/second - - Therefore, a single standard TCP connection cannot fully utilize, for - example, T1 rate (approximately 192,000 bytes/second) GSO satellite - channels. However, TCP has been extended to support larger windows - [JBB92]. The window scaling options outlined in [JBB92] should be - used in satellite environments, as well as the companion algorithms - PAWS (Protection Against Wrapped Sequence space) and RTTM (Round-Trip - Time Measurements). - - It should be noted that for a satellite link shared among many flows, - large windows may not be necessary. For instance, two long-lived TCP - connections each using a window of 65,535 bytes, as in the above - example, can fully utilize a T1 GSO satellite channel. - - Using large windows often requires both client and server - applications or TCP stacks to be hand tuned (usually by an expert) to - utilize large windows. Research into operating system mechanisms - that are able to adjust the buffer capacity as dictated by the - current network conditions is currently underway [SMM98]. This will - allow stock TCP implementations and applications to better utilize - the capacity provided by the underlying network. - -4.3 Acknowledgment Strategies - - There are two standard methods that can be used by TCP receivers to - generated acknowledgments. The method outlined in [Pos81] generates - an ACK for each incoming segment. [Bra89] states that hosts SHOULD - use "delayed acknowledgments". Using this algorithm, an ACK is - - - -Allman, et. al. Best Current Practice [Page 12] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - generated for every second full-sized segment, or if a second full- - size segment does not arrive within a given timeout (which must not - exceed 500 ms). The congestion window is increased based on the - number of incoming ACKs and delayed ACKs reduce the number of ACKs - being sent by the receiver. Therefore, cwnd growth occurs much more - slowly when using delayed ACKs compared to the case when the receiver - ACKs each incoming segment [All98]. - - A tempting "fix" to the problem caused by delayed ACKs is to simply - turn the mechanism off and let the receiver ACK each incoming - segment. However, this is not recommended. First, [Bra89] says that - a TCP receiver SHOULD generate delayed ACKs. And, second, increasing - the number of ACKs by a factor of two in a shared network may have - consequences that are not yet understood. Therefore, disabling - delayed ACKs is still a research issue and thus, at this time TCP - receivers should continue to generate delayed ACKs, per [Bra89]. - -4.4 Selective Acknowledgments - - Selective acknowledgments (SACKs) [MMFR96] allow TCP receivers to - inform TCP senders exactly which packets have arrived. SACKs allow - TCP to recover more quickly from lost segments, as well as avoiding - needless retransmissions. - - The fast retransmit algorithm can generally only repair one loss per - window of data. When multiple losses occur, the sender generally - must rely on a timeout to determine which segment needs to be - retransmitted next. While waiting for a timeout, the data segments - and their acknowledgments drain from the network. In the absence of - incoming ACKs to clock new segments into the network, the sender must - use the slow start algorithm to restart transmission. As discussed - above, the slow start algorithm can be time consuming over satellite - channels. When SACKs are employed, the sender is generally able to - determine which segments need to be retransmitted in the first RTT - following loss detection. This allows the sender to continue to - transmit segments (retransmissions and new segments, if appropriate) - at an appropriate rate and therefore sustain the ACK clock. This - avoids a costly slow start period following multiple lost segments. - Generally SACK is able to retransmit all dropped segments within the - first RTT following the loss detection. [MM96] and [FF96] discuss - specific congestion control algorithms that rely on SACK information - to determine which segments need to be retransmitted and when it is - appropriate to transmit those segments. Both these algorithms follow - the basic principles of congestion control outlined in [Jac88] and - reduce the window by half when congestion is detected. - - - - - - -Allman, et. al. Best Current Practice [Page 13] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - -5. Mitigation Summary - - Table 1 summarizes the mechanisms that have been discussed in this - document. Those mechanisms denoted "Recommended" are IETF standards - track mechanisms that are recommended by the authors for use in - networks containing satellite channels. Those mechanisms marked - "Required' have been defined by the IETF as required for hosts using - the shared Internet [Bra89]. Along with the section of this document - containing the discussion of each mechanism, we note where the - mechanism needs to be implemented. The codes listed in the last - column are defined as follows: "S" for the data sender, "R" for the - data receiver and "L" for the satellite link. - - Mechanism Use Section Where - +------------------------+-------------+------------+--------+ - | Path-MTU Discovery | Recommended | 3.1 | S | - | FEC | Recommended | 3.2 | L | - | TCP Congestion Control | | | | - | Slow Start | Required | 4.1.1 | S | - | Congestion Avoidance | Required | 4.1.1 | S | - | Fast Retransmit | Recommended | 4.1.2 | S | - | Fast Recovery | Recommended | 4.1.2 | S | - | TCP Large Windows | | | | - | Window Scaling | Recommended | 4.2 | S,R | - | PAWS | Recommended | 4.2 | S,R | - | RTTM | Recommended | 4.2 | S,R | - | TCP SACKs | Recommended | 4.4 | S,R | - +------------------------+-------------+------------+--------+ - Table 1 - - Satellite users should check with their TCP vendors (implementors) to - ensure the recommended mechanisms are supported in their stack in - current and/or future versions. Alternatively, the Pittsburgh - Supercomputer Center tracks TCP implementations and which extensions - they support, as well as providing guidance on tuning various TCP - implementations [PSC]. - - Research into improving the efficiency of TCP over satellite channels - is ongoing and will be summarized in a planned memo along with other - considerations, such as satellite network architectures. - -6. Security Considerations - - The authors believe that the recommendations contained in this memo - do not alter the security implications of TCP. However, when using a - broadcast medium such as satellites links to transfer user data - and/or network control traffic, one should be aware of the intrinsic - security implications of such technology. - - - -Allman, et. al. Best Current Practice [Page 14] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - Eavesdropping on network links is a form of passive attack that, if - performed successfully, could reveal critical traffic control - information that would jeopardize the proper functioning of the - network. These attacks could reduce the ability of the network to - provide data transmission services efficiently. Eavesdroppers could - also compromise the privacy of user data, especially if end-to-end - security mechanisms are not in use. While passive monitoring can - occur on any network, the wireless broadcast nature of satellite - links allows reception of signals without physical connection to the - network which enables monitoring to be conducted without detection. - However, it should be noted that the resources needed to monitor a - satellite link are non-trivial. - - Data encryption at the physical and/or link layers can provide secure - communication over satellite channels. However, this still leaves - traffic vulnerable to eavesdropping on networks before and after - traversing the satellite link. Therefore, end-to-end security - mechanisms should be considered. This document does not make any - recommendations as to which security mechanisms should be employed. - However, those operating and using satellite networks should survey - the currently available network security mechanisms and choose those - that meet their security requirements. - -Acknowledgments - - This document has benefited from comments from the members of the TCP - Over Satellite Working Group. In particular, we would like to thank - Aaron Falk, Matthew Halsey, Hans Kruse, Matt Mathis, Greg Nakanishi, - Vern Paxson, Jeff Semke, Bill Sepmeier and Eric Travis for their - useful comments about this document. - -References - - [AFP98] Allman, M., Floyd, S. and C. Partridge, "Increasing TCP's - Initial Window", RFC 2414, September 1998. - - [AHKO97] Mark Allman, Chris Hayes, Hans Kruse, and Shawn Ostermann. - TCP Performance Over Satellite Links. In Proceedings of - the 5th International Conference on Telecommunication - Systems, March 1997. - - [All97] Mark Allman. Improving TCP Performance Over Satellite - Channels. Master's thesis, Ohio University, June 1997. - - [All98] Mark Allman. On the Generation and Use of TCP - Acknowledgments. ACM Computer Communication Review, 28(5), - October 1998. - - - - -Allman, et. al. Best Current Practice [Page 15] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - [Bra89] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [FF96] Kevin Fall and Sally Floyd. Simulation-based Comparisons - of Tahoe, Reno and SACK TCP. Computer Communication - Review, July 1996. - - [FF98] Sally Floyd, Kevin Fall. Promoting the Use of End-to-End - Congestion Control in the Internet. Submitted to IEEE - Transactions on Networking. - - [Flo94] S. Floyd, TCP and Successive Fast Retransmits. Technical - report, October 1994. - ftp://ftp.ee.lbl.gov/papers/fastretrans.ps. - - [GJKFV98] Rohit Goyal, Raj Jain, Shiv Kalyanaraman, Sonia Fahmy, - Bobby Vandalore, Improving the Performance of TCP over the - ATM-UBR service, 1998. Sumbitted to Computer - Communications. - - [Jac90] Van Jacobson. Modified TCP Congestion Avoidance Algorithm. - Technical Report, LBL, April 1990. - - [JBB92] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions for - High Performance", RFC 1323, May 1992. - - [Jac88] Van Jacobson. Congestion Avoidance and Control. In ACM - SIGCOMM, 1988. - - [Kno93] Knowles, S., "IESG Advice from Experience with Path MTU - Discovery", RFC 1435, March 1993. - - [Mar78] James Martin. Communications Satellite Systems. Prentice - Hall, 1978. - - [MD90] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191, - November 1990. - - [MM96] Matt Mathis and Jamshid Mahdavi. Forward Acknowledgment: - Refining TCP Congestion Control. In ACM SIGCOMM, 1996. - - [MMFR96] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgment Options", RFC 2018, October 1996. - - [Mon98] M. J. Montpetit. TELEDESIC: Enabling The Global Community - Interaccess. In Proc. of the International Wireless - Symposium, May 1998. - - - - -Allman, et. al. Best Current Practice [Page 16] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - - [MSMO97] M. Mathis, J. Semke, J. Mahdavi, T. Ott, "The Macroscopic - Behavior of the TCP Congestion Avoidance Algorithm", - Computer Communication Review, volume 27, number3, July - 1997. available from - http://www.psc.edu/networking/papers/papers.html. - - [Pos81] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [PS97] Craig Partridge and Tim Shepard. TCP Performance Over - Satellite Links. IEEE Network, 11(5), September/October - 1997. - - [PSC] Jamshid Mahdavi. Enabling High Performance Data Transfers - on Hosts. http://www.psc.edu/networking/perf_tune.html. - - [SMM98] Jeff Semke, Jamshid Mahdavi and Matt Mathis. Automatic TCP - Buffer Tuning. In ACM SIGCOMM, August 1998. To appear. - - [Sta94] William Stallings. Data and Computer Communications. - MacMillian, 4th edition, 1994. - - [Ste97] Stevens, W., "TCP Slow Start, Congestion Avoidance, Fast - Retransmit, and Fast Recovery Algorithms", RFC 2001,January - 1997. - - [Stu95] M. A. Sturza. Architecture of the TELEDESIC Satellite - System. In Proceedings of the International Mobile - Satellite Conference, 1995. - - - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Best Current Practice [Page 17] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - -Authors' Addresses - - Mark Allman - NASA Lewis Research Center/Sterling Software - 21000 Brookpark Rd. MS 54-2 - Cleveland, OH 44135 - - Phone: +1 216 433 6586 - EMail: mallman@lerc.nasa.gov - http://roland.lerc.nasa.gov/~mallman - - - Daniel R. Glover - NASA Lewis Research Center - 21000 Brookpark Rd. - Cleveland, OH 44135 - - Phone: +1 216 433 2847 - EMail: Daniel.R.Glover@lerc.nasa.gov - - - Luis A. Sanchez - BBN Technologies - GTE Internetworking - 10 Moulton Street - Cambridge, MA 02140 - USA - - Phone: +1 617 873 3351 - EMail: lsanchez@ir.bbn.com - - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Best Current Practice [Page 18] - -RFC 2488 Enhancing TCP Over Satellite Channels January 1999 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1999). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Best Current Practice [Page 19] - diff --git a/ext/picotcp/RFC/rfc2581.txt b/ext/picotcp/RFC/rfc2581.txt deleted file mode 100644 index 07c1475..0000000 --- a/ext/picotcp/RFC/rfc2581.txt +++ /dev/null @@ -1,787 +0,0 @@ - - - - - - -Network Working Group M. Allman -Request for Comments: 2581 NASA Glenn/Sterling Software -Obsoletes: 2001 V. Paxson -Category: Standards Track ACIRI / ICSI - W. Stevens - Consultant - April 1999 - - - TCP Congestion Control - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1999). All Rights Reserved. - -Abstract - - This document defines TCP's four intertwined congestion control - algorithms: slow start, congestion avoidance, fast retransmit, and - fast recovery. In addition, the document specifies how TCP should - begin transmission after a relatively long idle period, as well as - discussing various acknowledgment generation methods. - -1. Introduction - - This document specifies four TCP [Pos81] congestion control - algorithms: slow start, congestion avoidance, fast retransmit and - fast recovery. These algorithms were devised in [Jac88] and [Jac90]. - Their use with TCP is standardized in [Bra89]. - - This document is an update of [Ste97]. In addition to specifying the - congestion control algorithms, this document specifies what TCP - connections should do after a relatively long idle period, as well as - specifying and clarifying some of the issues pertaining to TCP ACK - generation. - - Note that [Ste94] provides examples of these algorithms in action and - [WS95] provides an explanation of the source code for the BSD - implementation of these algorithms. - - - - -Allman, et. al. Standards Track [Page 1] - -RFC 2581 TCP Congestion Control April 1999 - - - This document is organized as follows. Section 2 provides various - definitions which will be used throughout the document. Section 3 - provides a specification of the congestion control algorithms. - Section 4 outlines concerns related to the congestion control - algorithms and finally, section 5 outlines security considerations. - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in [Bra97]. - -2. Definitions - - This section provides the definition of several terms that will be - used throughout the remainder of this document. - - SEGMENT: - A segment is ANY TCP/IP data or acknowledgment packet (or both). - - SENDER MAXIMUM SEGMENT SIZE (SMSS): The SMSS is the size of the - largest segment that the sender can transmit. This value can be - based on the maximum transmission unit of the network, the path - MTU discovery [MD90] algorithm, RMSS (see next item), or other - factors. The size does not include the TCP/IP headers and - options. - - RECEIVER MAXIMUM SEGMENT SIZE (RMSS): The RMSS is the size of the - largest segment the receiver is willing to accept. This is the - value specified in the MSS option sent by the receiver during - connection startup. Or, if the MSS option is not used, 536 bytes - [Bra89]. The size does not include the TCP/IP headers and - options. - - FULL-SIZED SEGMENT: A segment that contains the maximum number of - data bytes permitted (i.e., a segment containing SMSS bytes of - data). - - RECEIVER WINDOW (rwnd) The most recently advertised receiver window. - - CONGESTION WINDOW (cwnd): A TCP state variable that limits the - amount of data a TCP can send. At any given time, a TCP MUST NOT - send data with a sequence number higher than the sum of the - highest acknowledged sequence number and the minimum of cwnd and - rwnd. - - INITIAL WINDOW (IW): The initial window is the size of the sender's - congestion window after the three-way handshake is completed. - - - - - -Allman, et. al. Standards Track [Page 2] - -RFC 2581 TCP Congestion Control April 1999 - - - LOSS WINDOW (LW): The loss window is the size of the congestion - window after a TCP sender detects loss using its retransmission - timer. - - RESTART WINDOW (RW): The restart window is the size of the - congestion window after a TCP restarts transmission after an idle - period (if the slow start algorithm is used; see section 4.1 for - more discussion). - - FLIGHT SIZE: The amount of data that has been sent but not yet - acknowledged. - -3. Congestion Control Algorithms - - This section defines the four congestion control algorithms: slow - start, congestion avoidance, fast retransmit and fast recovery, - developed in [Jac88] and [Jac90]. In some situations it may be - beneficial for a TCP sender to be more conservative than the - algorithms allow, however a TCP MUST NOT be more aggressive than the - following algorithms allow (that is, MUST NOT send data when the - value of cwnd computed by the following algorithms would not allow - the data to be sent). - -3.1 Slow Start and Congestion Avoidance - - The slow start and congestion avoidance algorithms MUST be used by a - TCP sender to control the amount of outstanding data being injected - into the network. To implement these algorithms, two variables are - added to the TCP per-connection state. The congestion window (cwnd) - is a sender-side limit on the amount of data the sender can transmit - into the network before receiving an acknowledgment (ACK), while the - receiver's advertised window (rwnd) is a receiver-side limit on the - amount of outstanding data. The minimum of cwnd and rwnd governs - data transmission. - - Another state variable, the slow start threshold (ssthresh), is used - to determine whether the slow start or congestion avoidance algorithm - is used to control data transmission, as discussed below. - - Beginning transmission into a network with unknown conditions - requires TCP to slowly probe the network to determine the available - capacity, in order to avoid congesting the network with an - inappropriately large burst of data. The slow start algorithm is - used for this purpose at the beginning of a transfer, or after - repairing loss detected by the retransmission timer. - - - - - - -Allman, et. al. Standards Track [Page 3] - -RFC 2581 TCP Congestion Control April 1999 - - - IW, the initial value of cwnd, MUST be less than or equal to 2*SMSS - bytes and MUST NOT be more than 2 segments. - - We note that a non-standard, experimental TCP extension allows that a - TCP MAY use a larger initial window (IW), as defined in equation 1 - [AFP98]: - - IW = min (4*SMSS, max (2*SMSS, 4380 bytes)) (1) - - With this extension, a TCP sender MAY use a 3 or 4 segment initial - window, provided the combined size of the segments does not exceed - 4380 bytes. We do NOT allow this change as part of the standard - defined by this document. However, we include discussion of (1) in - the remainder of this document as a guideline for those experimenting - with the change, rather than conforming to the present standards for - TCP congestion control. - - The initial value of ssthresh MAY be arbitrarily high (for example, - some implementations use the size of the advertised window), but it - may be reduced in response to congestion. The slow start algorithm - is used when cwnd < ssthresh, while the congestion avoidance - algorithm is used when cwnd > ssthresh. When cwnd and ssthresh are - equal the sender may use either slow start or congestion avoidance. - - During slow start, a TCP increments cwnd by at most SMSS bytes for - each ACK received that acknowledges new data. Slow start ends when - cwnd exceeds ssthresh (or, optionally, when it reaches it, as noted - above) or when congestion is observed. - - During congestion avoidance, cwnd is incremented by 1 full-sized - segment per round-trip time (RTT). Congestion avoidance continues - until congestion is detected. One formula commonly used to update - cwnd during congestion avoidance is given in equation 2: - - cwnd += SMSS*SMSS/cwnd (2) - - This adjustment is executed on every incoming non-duplicate ACK. - Equation (2) provides an acceptable approximation to the underlying - principle of increasing cwnd by 1 full-sized segment per RTT. (Note - that for a connection in which the receiver acknowledges every data - segment, (2) proves slightly more aggressive than 1 segment per RTT, - and for a receiver acknowledging every-other packet, (2) is less - aggressive.) - - - - - - - - -Allman, et. al. Standards Track [Page 4] - -RFC 2581 TCP Congestion Control April 1999 - - - Implementation Note: Since integer arithmetic is usually used in TCP - implementations, the formula given in equation 2 can fail to increase - cwnd when the congestion window is very large (larger than - SMSS*SMSS). If the above formula yields 0, the result SHOULD be - rounded up to 1 byte. - - Implementation Note: older implementations have an additional - additive constant on the right-hand side of equation (2). This is - incorrect and can actually lead to diminished performance [PAD+98]. - - Another acceptable way to increase cwnd during congestion avoidance - is to count the number of bytes that have been acknowledged by ACKs - for new data. (A drawback of this implementation is that it requires - maintaining an additional state variable.) When the number of bytes - acknowledged reaches cwnd, then cwnd can be incremented by up to SMSS - bytes. Note that during congestion avoidance, cwnd MUST NOT be - increased by more than the larger of either 1 full-sized segment per - RTT, or the value computed using equation 2. - - Implementation Note: some implementations maintain cwnd in units of - bytes, while others in units of full-sized segments. The latter will - find equation (2) difficult to use, and may prefer to use the - counting approach discussed in the previous paragraph. - - When a TCP sender detects segment loss using the retransmission - timer, the value of ssthresh MUST be set to no more than the value - given in equation 3: - - ssthresh = max (FlightSize / 2, 2*SMSS) (3) - - As discussed above, FlightSize is the amount of outstanding data in - the network. - - Implementation Note: an easy mistake to make is to simply use cwnd, - rather than FlightSize, which in some implementations may - incidentally increase well beyond rwnd. - - Furthermore, upon a timeout cwnd MUST be set to no more than the loss - window, LW, which equals 1 full-sized segment (regardless of the - value of IW). Therefore, after retransmitting the dropped segment - the TCP sender uses the slow start algorithm to increase the window - from 1 full-sized segment to the new value of ssthresh, at which - point congestion avoidance again takes over. - - - - - - - - -Allman, et. al. Standards Track [Page 5] - -RFC 2581 TCP Congestion Control April 1999 - - -3.2 Fast Retransmit/Fast Recovery - - A TCP receiver SHOULD send an immediate duplicate ACK when an out- - of-order segment arrives. The purpose of this ACK is to inform the - sender that a segment was received out-of-order and which sequence - number is expected. From the sender's perspective, duplicate ACKs - can be caused by a number of network problems. First, they can be - caused by dropped segments. In this case, all segments after the - dropped segment will trigger duplicate ACKs. Second, duplicate ACKs - can be caused by the re-ordering of data segments by the network (not - a rare event along some network paths [Pax97]). Finally, duplicate - ACKs can be caused by replication of ACK or data segments by the - network. In addition, a TCP receiver SHOULD send an immediate ACK - when the incoming segment fills in all or part of a gap in the - sequence space. This will generate more timely information for a - sender recovering from a loss through a retransmission timeout, a - fast retransmit, or an experimental loss recovery algorithm, such as - NewReno [FH98]. - - The TCP sender SHOULD use the "fast retransmit" algorithm to detect - and repair loss, based on incoming duplicate ACKs. The fast - retransmit algorithm uses the arrival of 3 duplicate ACKs (4 - identical ACKs without the arrival of any other intervening packets) - as an indication that a segment has been lost. After receiving 3 - duplicate ACKs, TCP performs a retransmission of what appears to be - the missing segment, without waiting for the retransmission timer to - expire. - - After the fast retransmit algorithm sends what appears to be the - missing segment, the "fast recovery" algorithm governs the - transmission of new data until a non-duplicate ACK arrives. The - reason for not performing slow start is that the receipt of the - duplicate ACKs not only indicates that a segment has been lost, but - also that segments are most likely leaving the network (although a - massive segment duplication by the network can invalidate this - conclusion). In other words, since the receiver can only generate a - duplicate ACK when a segment has arrived, that segment has left the - network and is in the receiver's buffer, so we know it is no longer - consuming network resources. Furthermore, since the ACK "clock" - [Jac88] is preserved, the TCP sender can continue to transmit new - segments (although transmission must continue using a reduced cwnd). - - The fast retransmit and fast recovery algorithms are usually - implemented together as follows. - - 1. When the third duplicate ACK is received, set ssthresh to no more - than the value given in equation 3. - - - - -Allman, et. al. Standards Track [Page 6] - -RFC 2581 TCP Congestion Control April 1999 - - - 2. Retransmit the lost segment and set cwnd to ssthresh plus 3*SMSS. - This artificially "inflates" the congestion window by the number - of segments (three) that have left the network and which the - receiver has buffered. - - 3. For each additional duplicate ACK received, increment cwnd by - SMSS. This artificially inflates the congestion window in order - to reflect the additional segment that has left the network. - - 4. Transmit a segment, if allowed by the new value of cwnd and the - receiver's advertised window. - - 5. When the next ACK arrives that acknowledges new data, set cwnd to - ssthresh (the value set in step 1). This is termed "deflating" - the window. - - This ACK should be the acknowledgment elicited by the - retransmission from step 1, one RTT after the retransmission - (though it may arrive sooner in the presence of significant out- - of-order delivery of data segments at the receiver). - Additionally, this ACK should acknowledge all the intermediate - segments sent between the lost segment and the receipt of the - third duplicate ACK, if none of these were lost. - - Note: This algorithm is known to generally not recover very - efficiently from multiple losses in a single flight of packets - [FF96]. One proposed set of modifications to address this problem - can be found in [FH98]. - -4. Additional Considerations - -4.1 Re-starting Idle Connections - - A known problem with the TCP congestion control algorithms described - above is that they allow a potentially inappropriate burst of traffic - to be transmitted after TCP has been idle for a relatively long - period of time. After an idle period, TCP cannot use the ACK clock - to strobe new segments into the network, as all the ACKs have drained - from the network. Therefore, as specified above, TCP can potentially - send a cwnd-size line-rate burst into the network after an idle - period. - - [Jac88] recommends that a TCP use slow start to restart transmission - after a relatively long idle period. Slow start serves to restart - the ACK clock, just as it does at the beginning of a transfer. This - mechanism has been widely deployed in the following manner. When TCP - has not received a segment for more than one retransmission timeout, - cwnd is reduced to the value of the restart window (RW) before - - - -Allman, et. al. Standards Track [Page 7] - -RFC 2581 TCP Congestion Control April 1999 - - - transmission begins. - - For the purposes of this standard, we define RW = IW. - - We note that the non-standard experimental extension to TCP defined - in [AFP98] defines RW = min(IW, cwnd), with the definition of IW - adjusted per equation (1) above. - - Using the last time a segment was received to determine whether or - not to decrease cwnd fails to deflate cwnd in the common case of - persistent HTTP connections [HTH98]. In this case, a WWW server - receives a request before transmitting data to the WWW browser. The - reception of the request makes the test for an idle connection fail, - and allows the TCP to begin transmission with a possibly - inappropriately large cwnd. - - Therefore, a TCP SHOULD set cwnd to no more than RW before beginning - transmission if the TCP has not sent data in an interval exceeding - the retransmission timeout. - -4.2 Generating Acknowledgments - - The delayed ACK algorithm specified in [Bra89] SHOULD be used by a - TCP receiver. When used, a TCP receiver MUST NOT excessively delay - acknowledgments. Specifically, an ACK SHOULD be generated for at - least every second full-sized segment, and MUST be generated within - 500 ms of the arrival of the first unacknowledged packet. - - The requirement that an ACK "SHOULD" be generated for at least every - second full-sized segment is listed in [Bra89] in one place as a - SHOULD and another as a MUST. Here we unambiguously state it is a - SHOULD. We also emphasize that this is a SHOULD, meaning that an - implementor should indeed only deviate from this requirement after - careful consideration of the implications. See the discussion of - "Stretch ACK violation" in [PAD+98] and the references therein for a - discussion of the possible performance problems with generating ACKs - less frequently than every second full-sized segment. - - In some cases, the sender and receiver may not agree on what - constitutes a full-sized segment. An implementation is deemed to - comply with this requirement if it sends at least one acknowledgment - every time it receives 2*RMSS bytes of new data from the sender, - where RMSS is the Maximum Segment Size specified by the receiver to - the sender (or the default value of 536 bytes, per [Bra89], if the - receiver does not specify an MSS option during connection - establishment). The sender may be forced to use a segment size less - than RMSS due to the maximum transmission unit (MTU), the path MTU - discovery algorithm or other factors. For instance, consider the - - - -Allman, et. al. Standards Track [Page 8] - -RFC 2581 TCP Congestion Control April 1999 - - - case when the receiver announces an RMSS of X bytes but the sender - ends up using a segment size of Y bytes (Y < X) due to path MTU - discovery (or the sender's MTU size). The receiver will generate - stretch ACKs if it waits for 2*X bytes to arrive before an ACK is - sent. Clearly this will take more than 2 segments of size Y bytes. - Therefore, while a specific algorithm is not defined, it is desirable - for receivers to attempt to prevent this situation, for example by - acknowledging at least every second segment, regardless of size. - Finally, we repeat that an ACK MUST NOT be delayed for more than 500 - ms waiting on a second full-sized segment to arrive. - - Out-of-order data segments SHOULD be acknowledged immediately, in - order to accelerate loss recovery. To trigger the fast retransmit - algorithm, the receiver SHOULD send an immediate duplicate ACK when - it receives a data segment above a gap in the sequence space. To - provide feedback to senders recovering from losses, the receiver - SHOULD send an immediate ACK when it receives a data segment that - fills in all or part of a gap in the sequence space. - - A TCP receiver MUST NOT generate more than one ACK for every incoming - segment, other than to update the offered window as the receiving - application consumes new data [page 42, Pos81][Cla82]. - -4.3 Loss Recovery Mechanisms - - A number of loss recovery algorithms that augment fast retransmit and - fast recovery have been suggested by TCP researchers. While some of - these algorithms are based on the TCP selective acknowledgment (SACK) - option [MMFR96], such as [FF96,MM96a,MM96b], others do not require - SACKs [Hoe96,FF96,FH98]. The non-SACK algorithms use "partial - acknowledgments" (ACKs which cover new data, but not all the data - outstanding when loss was detected) to trigger retransmissions. - While this document does not standardize any of the specific - algorithms that may improve fast retransmit/fast recovery, these - enhanced algorithms are implicitly allowed, as long as they follow - the general principles of the basic four algorithms outlined above. - - Therefore, when the first loss in a window of data is detected, - ssthresh MUST be set to no more than the value given by equation (3). - Second, until all lost segments in the window of data in question are - repaired, the number of segments transmitted in each RTT MUST be no - more than half the number of outstanding segments when the loss was - detected. Finally, after all loss in the given window of segments - has been successfully retransmitted, cwnd MUST be set to no more than - ssthresh and congestion avoidance MUST be used to further increase - cwnd. Loss in two successive windows of data, or the loss of a - retransmission, should be taken as two indications of congestion and, - therefore, cwnd (and ssthresh) MUST be lowered twice in this case. - - - -Allman, et. al. Standards Track [Page 9] - -RFC 2581 TCP Congestion Control April 1999 - - - The algorithms outlined in [Hoe96,FF96,MM96a,MM6b] follow the - principles of the basic four congestion control algorithms outlined - in this document. - -5. Security Considerations - - This document requires a TCP to diminish its sending rate in the - presence of retransmission timeouts and the arrival of duplicate - acknowledgments. An attacker can therefore impair the performance of - a TCP connection by either causing data packets or their - acknowledgments to be lost, or by forging excessive duplicate - acknowledgments. Causing two congestion control events back-to-back - will often cut ssthresh to its minimum value of 2*SMSS, causing the - connection to immediately enter the slower-performing congestion - avoidance phase. - - The Internet to a considerable degree relies on the correct - implementation of these algorithms in order to preserve network - stability and avoid congestion collapse. An attacker could cause TCP - endpoints to respond more aggressively in the face of congestion by - forging excessive duplicate acknowledgments or excessive - acknowledgments for new data. Conceivably, such an attack could - drive a portion of the network into congestion collapse. - -6. Changes Relative to RFC 2001 - - This document has been extensively rewritten editorially and it is - not feasible to itemize the list of changes between the two - documents. The intention of this document is not to change any of the - recommendations given in RFC 2001, but to further clarify cases that - were not discussed in detail in 2001. Specifically, this document - suggests what TCP connections should do after a relatively long idle - period, as well as specifying and clarifying some of the issues - pertaining to TCP ACK generation. Finally, the allowable upper bound - for the initial congestion window has also been raised from one to - two segments. - -Acknowledgments - - The four algorithms that are described were developed by Van - Jacobson. - - Some of the text from this document is taken from "TCP/IP - Illustrated, Volume 1: The Protocols" by W. Richard Stevens - (Addison-Wesley, 1994) and "TCP/IP Illustrated, Volume 2: The - Implementation" by Gary R. Wright and W. Richard Stevens (Addison- - Wesley, 1995). This material is used with the permission of - Addison-Wesley. - - - -Allman, et. al. Standards Track [Page 10] - -RFC 2581 TCP Congestion Control April 1999 - - - Neal Cardwell, Sally Floyd, Craig Partridge and Joe Touch contributed - a number of helpful suggestions. - -References - - [AFP98] Allman, M., Floyd, S. and C. Partridge, "Increasing TCP's - Initial Window Size, RFC 2414, September 1998. - - [Bra89] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [Bra97] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [Cla82] Clark, D., "Window and Acknowledgment Strategy in TCP", RFC - 813, July 1982. - - [FF96] Fall, K. and S. Floyd, "Simulation-based Comparisons of - Tahoe, Reno and SACK TCP", Computer Communication Review, - July 1996. ftp://ftp.ee.lbl.gov/papers/sacks.ps.Z. - - [FH98] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [Flo94] Floyd, S., "TCP and Successive Fast Retransmits. Technical - report", October 1994. - ftp://ftp.ee.lbl.gov/papers/fastretrans.ps. - - [Hoe96] Hoe, J., "Improving the Start-up Behavior of a Congestion - Control Scheme for TCP", In ACM SIGCOMM, August 1996. - - [HTH98] Hughes, A., Touch, J. and J. Heidemann, "Issues in TCP - Slow-Start Restart After Idle", Work in Progress. - - [Jac88] Jacobson, V., "Congestion Avoidance and Control", Computer - Communication Review, vol. 18, no. 4, pp. 314-329, Aug. - 1988. ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z. - - [Jac90] Jacobson, V., "Modified TCP Congestion Avoidance Algorithm", - end2end-interest mailing list, April 30, 1990. - ftp://ftp.isi.edu/end2end/end2end-interest-1990.mail. - - [MD90] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191, - November 1990. - - - - - - - -Allman, et. al. Standards Track [Page 11] - -RFC 2581 TCP Congestion Control April 1999 - - - [MM96a] Mathis, M. and J. Mahdavi, "Forward Acknowledgment: Refining - TCP Congestion Control", Proceedings of SIGCOMM'96, August, - 1996, Stanford, CA. Available - fromhttp://www.psc.edu/networking/papers/papers.html - - [MM96b] Mathis, M. and J. Mahdavi, "TCP Rate-Halving with Bounding - Parameters", Technical report. Available from - http://www.psc.edu/networking/papers/FACKnotes/current. - - [MMFR96] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, October 1996. - - [PAD+98] Paxson, V., Allman, M., Dawson, S., Fenner, W., Griner, J., - Heavens, I., Lahey, K., Semke, J. and B. Volz, "Known TCP - Implementation Problems", RFC 2525, March 1999. - - [Pax97] Paxson, V., "End-to-End Internet Packet Dynamics", - Proceedings of SIGCOMM '97, Cannes, France, Sep. 1997. - - [Pos81] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, - September 1981. - - [Ste94] Stevens, W., "TCP/IP Illustrated, Volume 1: The Protocols", - Addison-Wesley, 1994. - - [Ste97] Stevens, W., "TCP Slow Start, Congestion Avoidance, Fast - Retransmit, and Fast Recovery Algorithms", RFC 2001, January - 1997. - - [WS95] Wright, G. and W. Stevens, "TCP/IP Illustrated, Volume 2: - The Implementation", Addison-Wesley, 1995. - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Standards Track [Page 12] - -RFC 2581 TCP Congestion Control April 1999 - - -Authors' Addresses - - Mark Allman - NASA Glenn Research Center/Sterling Software - Lewis Field - 21000 Brookpark Rd. MS 54-2 - Cleveland, OH 44135 - 216-433-6586 - - EMail: mallman@grc.nasa.gov - http://roland.grc.nasa.gov/~mallman - - - Vern Paxson - ACIRI / ICSI - 1947 Center Street - Suite 600 - Berkeley, CA 94704-1198 - - Phone: +1 510/642-4274 x302 - EMail: vern@aciri.org - - - W. Richard Stevens - 1202 E. Paseo del Zorro - Tucson, AZ 85718 - 520-297-9416 - - EMail: rstevens@kohala.com - http://www.kohala.com/~rstevens - - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Standards Track [Page 13] - -RFC 2581 TCP Congestion Control April 1999 - - -Full Copyright Statement - - Copyright (C) The Internet Society (1999). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Standards Track [Page 14] - diff --git a/ext/picotcp/RFC/rfc2675.txt b/ext/picotcp/RFC/rfc2675.txt deleted file mode 100644 index ded628c..0000000 --- a/ext/picotcp/RFC/rfc2675.txt +++ /dev/null @@ -1,507 +0,0 @@ - - - - - - -Network Working Group D. Borman -Request for Comments: 2675 Berkeley Software Design -Obsoletes: 2147 S. Deering -Category: Standards Track Cisco - R. Hinden - Nokia - August 1999 - IPv6 Jumbograms - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (1999). All Rights Reserved. - -Abstract - - A "jumbogram" is an IPv6 packet containing a payload longer than - 65,535 octets. This document describes the IPv6 Jumbo Payload - option, which provides the means of specifying such large payload - lengths. It also describes the changes needed to TCP and UDP to make - use of jumbograms. - - Jumbograms are relevant only to IPv6 nodes that may be attached to - links with a link MTU greater than 65,575 octets, and need not be - implemented or understood by IPv6 nodes that do not support - attachment to links with such large MTUs. - -1. Introduction - - jumbo (jum'bO), - - n., pl. -bos, adj. - -n. - 1. a person, animal, or thing very large of its kind. - -adj. - 2. very large: the jumbo box of cereal. - - [1800-10; orig. uncert.; popularized as the name of a large - elephant purchased and exhibited by P.T. Barnum in 1882] - - -- www.infoplease.com - - - -Borman, et al. Standards Track [Page 1] - -RFC 2675 IPv6 Jumbograms August 1999 - - - The IPv6 header [IPv6] has a 16-bit Payload Length field and, - therefore, supports payloads up to 65,535 octets long. This document - specifies an IPv6 hop-by-hop option, called the Jumbo Payload option, - that carries a 32-bit length field in order to allow transmission of - IPv6 packets with payloads between 65,536 and 4,294,967,295 octets in - length. Packets with such long payloads are referred to as - "jumbograms". - - The Jumbo Payload option is relevant only for IPv6 nodes that may be - attached to links with a link MTU greater than 65,575 octets (that - is, 65,535 + 40, where 40 octets is the size of the IPv6 header). - The Jumbo Payload option need not be implemented or understood by - IPv6 nodes that do not support attachment to links with MTU greater - than 65,575. - - On links with configurable MTUs, the MTU must not be configured to a - value greater than 65,575 octets if there are nodes attached to that - link that do not support the Jumbo Payload option and it can not be - guaranteed that the Jumbo Payload option will not be sent to those - nodes. - - The UDP header [UDP] has a 16-bit Length field which prevents it from - making use of jumbograms, and though the TCP header [TCP] does not - have a Length field, both the TCP MSS option and the TCP Urgent field - are constrained to 16 bits. This document specifies some simple - enhancements to TCP and UDP to enable them to make use of jumbograms. - An implementation of TCP or UDP on an IPv6 node that supports the - Jumbo Payload option must include the enhancements specified here. - - Note: The 16 bit checksum used by UDP and TCP becomes less accurate - as the length of the data being checksummed is increased. - Application designers may want to take this into consideration. - -1.1 Document History - - This document merges and updates material that was previously - published in two separate documents: - - - The specification of the Jumbo Payload option previously appeared - as part of the IPv6 specification in RFC 1883. RFC 1883 has been - superseded by RFC 2460, which no longer includes specification of - the Jumbo Payload option. - - - The specification of TCP and UDP enhancements to support - jumbograms previously appeared as RFC 2147. RFC 2147 is obsoleted - by this document. - - - - - -Borman, et al. Standards Track [Page 2] - -RFC 2675 IPv6 Jumbograms August 1999 - - -2. Format of the Jumbo Payload Option - - The Jumbo Payload option is carried in an IPv6 Hop-by-Hop Options - header, immediately following the IPv6 header. This option has an - alignment requirement of 4n + 2. (See [IPv6, Section 4.2] for - discussion of option alignment.) The option has the following - format: - - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Type | Opt Data Len | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Jumbo Payload Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type 8-bit value C2 (hexadecimal). - - Opt Data Len 8-bit value 4. - - Jumbo Payload Length 32-bit unsigned integer. Length of the IPv6 - packet in octets, excluding the IPv6 header - but including the Hop-by-Hop Options header - and any other extension headers present. - Must be greater than 65,535. - -3. Usage of the Jumbo Payload Option - - The Payload Length field in the IPv6 header must be set to zero in - every packet that carries the Jumbo Payload option. - - If a node that understands the Jumbo Payload option receives a packet - whose IPv6 header carries a Payload Length of zero and a Next Header - value of zero (meaning that a Hop-by-Hop Options header follows), and - whose link-layer framing indicates the presence of octets beyond the - IPv6 header, the node must proceed to process the Hop-by-Hop Options - header in order to determine the actual length of the payload from - the Jumbo Payload option. - - The Jumbo Payload option must not be used in a packet that carries a - Fragment header. - - Higher-layer protocols that use the IPv6 Payload Length field to - compute the value of the Upper-Layer Packet Length field in the - checksum pseudo-header described in [IPv6, Section 8.1] must instead - use the Jumbo Payload Length field for that computation, for packets - that carry the Jumbo Payload option. - - - - - - -Borman, et al. Standards Track [Page 3] - -RFC 2675 IPv6 Jumbograms August 1999 - - - Nodes that understand the Jumbo Payload option are required to detect - a number of possible format errors, and if the erroneous packet was - not destined to a multicast address, report the error by sending an - ICMP Parameter Problem message [ICMPv6] to the packet's source. The - following list of errors specifies the values to be used in the Code - and Pointer fields of the Parameter Problem message: - - error: IPv6 Payload Length = 0 and - IPv6 Next Header = Hop-by-Hop Options and - Jumbo Payload option not present - - Code: 0 - Pointer: high-order octet of the IPv6 Payload Length - - error: IPv6 Payload Length != 0 and - Jumbo Payload option present - - Code: 0 - Pointer: Option Type field of the Jumbo Payload option - - error: Jumbo Payload option present and - Jumbo Payload Length < 65,536 - - Code: 0 - Pointer: high-order octet of the Jumbo Payload Length - - error: Jumbo Payload option present and - Fragment header present - - Code: 0 - Pointer: high-order octet of the Fragment header. - - A node that does not understand the Jumbo Payload option is expected - to respond to erroneously-received jumbograms as follows, according - to the IPv6 specification: - - error: IPv6 Payload Length = 0 and - IPv6 Next Header = Hop-by-Hop Options - - Code: 0 - Pointer: high-order octet of the IPv6 Payload Length - - error: IPv6 Payload Length != 0 and - Jumbo Payload option present - - Code: 2 - Pointer: Option Type field of the Jumbo Payload option - - - - -Borman, et al. Standards Track [Page 4] - -RFC 2675 IPv6 Jumbograms August 1999 - - -4. UDP Jumbograms - - The 16-bit Length field of the UDP header limits the total length of - a UDP packet (that is, a UDP header plus data) to no greater than - 65,535 octets. This document specifies the following modification of - UDP to relax that limit: UDP packets longer than 65,535 octets may be - sent by setting the UDP Length field to zero, and letting the - receiver derive the actual UDP packet length from the IPv6 payload - length. (Note that, prior to this modification, zero was not a legal - value for the UDP Length field, because the UDP packet length - includes the UDP header and therefore has a minimum value of 8.) - - The specific requirements for sending a UDP jumbogram are as follows: - - When sending a UDP packet, if and only if the length of the UDP - header plus UDP data is greater than 65,535, set the Length field - in the UDP header to zero. - - The IPv6 packet carrying such a large UDP packet will necessarily - include a Jumbo Payload option in a Hop-by-Hop Options header; set - the Jumbo Payload Length field of that option to be the actual - length of the UDP header plus data, plus the length of all IPv6 - extension headers present between the IPv6 header and the UDP - header. - - For generating the UDP checksum, use the actual length of the UDP - header plus data, NOT zero, in the checksum pseudo-header [IPv6, - Section 8.1]. - - The specific requirements for receiving a UDP jumbogram are as - follows: - - When receiving a UDP packet, if and only if the Length field in - the UDP header is zero, calculate the actual length of the UDP - header plus data from the IPv6 Jumbo Payload Length field minus - the length of all extension headers present between the IPv6 - header and the UDP header. - - In the unexpected case that the UDP Length field is zero but no - Jumbo Payload option is present (i.e., the IPv6 packet is not a - jumbogram), use the Payload Length field in the IPv6 header, in - place of the Jumbo Payload Length field, in the above calculation. - - For verifying the received UDP checksum, use the calculated length - of the UDP header plus data, NOT zero, in the checksum pseudo- - header. - - - - - -Borman, et al. Standards Track [Page 5] - -RFC 2675 IPv6 Jumbograms August 1999 - - -5. TCP Jumbograms - - Because there is no length field in the TCP header, there is nothing - limiting the length of an individual TCP packet. However, the MSS - value that is negotiated at the beginning of the connection limits - the largest TCP packet that can be sent, and the Urgent Pointer - cannot reference data beyond 65,535 bytes. - -5.1 TCP MSS - - When determining what MSS value to send, if the MTU of the directly - attached interface minus 60 [IPv6, Section 8.3] is greater than or - equal to 65,535, then set the MSS value to 65,535. - - When an MSS value of 65,535 is received, it is to be treated as - infinity. The actual MSS is determined by subtracting 60 from the - value learned by performing Path MTU Discovery [MTU-DISC] over the - path to the TCP peer. - -5.2 TCP Urgent Pointer - - The Urgent Pointer problem could be fixed by adding a TCP Urgent - Pointer Option. However, since it is unlikely that applications - using jumbograms will also use Urgent Pointers, a less intrusive - change similar to the MSS change will suffice. - - When a TCP packet is to be sent with an Urgent Pointer (i.e., the URG - bit set), first calculate the offset from the Sequence Number to the - Urgent Pointer. If the offset is less than 65,535, fill in the - Urgent field and continue with the normal TCP processing. If the - offset is greater than 65,535, and the offset is greater than or - equal to the length of the TCP data, fill in the Urgent Pointer with - 65,535 and continue with the normal TCP processing. Otherwise, the - TCP packet must be split into two pieces. The first piece contains - data up to, but not including the data pointed to by the Urgent - Pointer, and the Urgent field is set to 65,535 to indicate that the - Urgent Pointer is beyond the end of this packet. The second piece - can then be sent with the Urgent field set normally. - - Note: The first piece does not have to include all of the data up to - the Urgent Pointer. It can be shorter, just as long as it ends - within 65,534 bytes of the Urgent Pointer, so that the offset to the - Urgent Pointer in the second piece will be less than 65,535 bytes. - - For TCP input processing, when a TCP packet is received with the URG - bit set and an Urgent field of 65,535, the Urgent Pointer is - calculated using an offset equal to the length of the TCP data, - rather than the offset in the Urgent field. - - - -Borman, et al. Standards Track [Page 6] - -RFC 2675 IPv6 Jumbograms August 1999 - - - It should also be noted that though the TCP window is only 16-bits, - larger windows can be used through use of the TCP Window Scale option - [TCP-EXT]. - -6. Security Considerations - - The Jumbo Payload option and TCP/UDP jumbograms do not introduce any - known new security concerns. - -7. Authors' Addresses - - David A. Borman - Berkeley Software Design, Inc. - 4719 Weston Hills Drive - Eagan, MN 55123 - USA - - Phone: +1 612 405 8194 - EMail: dab@bsdi.com - - - Stephen E. Deering - Cisco Systems, Inc. - 170 West Tasman Drive - San Jose, CA 95134-1706 - USA - - Phone: +1 408 527 8213 - EMail: deering@cisco.com - - - Robert M. Hinden - Nokia - 313 Fairchild Drive - Mountain View, CA 94043 - USA - - Phone: +1 650 625 2004 - EMail: hinden@iprg.nokia.com - - - - - - - - - - - - -Borman, et al. Standards Track [Page 7] - -RFC 2675 IPv6 Jumbograms August 1999 - - -8. References - - [ICMPv6] Conta, A. and S. Deering, "ICMP for the Internet Protocol - Version 6 (IPv6)", RFC 2463, December 1998. - - [IPv6] Deering, S. and R. Hinden, "Internet Protocol Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [MTU-DISC] McCann, J., Deering, S. and J. Mogul, "Path MTU Discovery - for IP Version 6", RFC 1981, August 1986. - - [TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [TCP-EXT] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [UDP] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Borman, et al. Standards Track [Page 8] - -RFC 2675 IPv6 Jumbograms August 1999 - - -9. Full Copyright Statement - - Copyright (C) The Internet Society (1999). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Borman, et al. Standards Track [Page 9] - diff --git a/ext/picotcp/RFC/rfc2861.txt b/ext/picotcp/RFC/rfc2861.txt deleted file mode 100644 index e5a4998..0000000 --- a/ext/picotcp/RFC/rfc2861.txt +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - -Network Working Group M. Handley -Request for Comments: 2861 J. Padhye -Category: Experimental S. Floyd - ACIRI - June 2000 - - - TCP Congestion Window Validation - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - TCP's congestion window controls the number of packets a TCP flow may - have in the network at any time. However, long periods when the - sender is idle or application-limited can lead to the invalidation of - the congestion window, in that the congestion window no longer - reflects current information about the state of the network. This - document describes a simple modification to TCP's congestion control - algorithms to decay the congestion window cwnd after the transition - from a sufficiently-long application-limited period, while using the - slow-start threshold ssthresh to save information about the previous - value of the congestion window. - - An invalid congestion window also results when the congestion window - is increased (i.e., in TCP's slow-start or congestion avoidance - phases) during application-limited periods, when the previous value - of the congestion window might never have been fully utilized. We - propose that the TCP sender should not increase the congestion window - when the TCP sender has been application-limited (and therefore has - not fully used the current congestion window). We have explored - these algorithms both with simulations and with experiments from an - implementation in FreeBSD. - -1. Conventions and Acronyms - - The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, - SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this - document, are to be interpreted as described in [B97]. - - - -Handley, et al. Experimental [Page 1] - -RFC 2861 TCP Congestion Window Validation June 2000 - - -2. Introduction - - TCP's congestion window controls the number of packets a TCP flow may - have in the network at any time. The congestion window is set using - an Additive-Increase, Multiplicative-Decrease (AIMD) mechanism that - probes for available bandwidth, dynamically adapting to changing - network conditions. This AIMD mechanism works well when the sender - continually has data to send, as is typically the case for TCP used - for bulk-data transfer. In contrast, for TCP used with telnet - applications, the data sender often has little or no data to send, - and the sending rate is often determined by the rate at which data is - generated by the user. With the advent of the web, including - developments such as TCP senders with dynamically-created data and - HTTP 1.1 with persistent-connection TCP, the interaction between - application-limited periods (when the sender sends less than is - allowed by the congestion or receiver windows) and network-limited - periods (when the sender is limited by the TCP window) becomes - increasingly important. More precisely, we define a network-limited - period as any period when the sender is sending a full window of - data. - - Long periods when the sender is application-limited can lead to the - invalidation of the congestion window. During periods when the TCP - sender is network-limited, the value of the congestion window is - repeatedly "revalidated" by the successful transmission of a window - of data without loss. When the TCP sender is network-limited, there - is an incoming stream of acknowledgements that "clocks out" new data, - giving concrete evidence of recent available bandwidth in the - network. In contrast, during periods when the TCP sender is - application-limited, the estimate of available capacity represented - by the congestion window may become steadily less accurate over time. - In particular, capacity that had once been used by the network- - limited connection might now be used by other traffic. - - Current TCP implementations have a range of behaviors for starting up - after an idle period. Some current TCP implementations slow-start - after an idle period longer than the RTO estimate, as suggested in - [RFC2581] and in the appendix of [VJ88], while other implementations - don't reduce their congestion window after an idle period. RFC 2581 - [RFC2581] recommends the following: "a TCP SHOULD set cwnd to no more - than RW [the initial window] before beginning transmission if the TCP - has not sent data in an interval exceeding the retransmission - timeout." A proposal for TCP's slow-start after idle has also been - discussed in [HTH98]. The issue of validation of congestion - information during idle periods has also been addressed in contexts - other than TCP and IP, for example in "Use-it or Lose-it" mechanisms - for ATM networks [J96,J95]. - - - - -Handley, et al. Experimental [Page 2] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - To address the revalidation of the congestion window after a - application-limited period, we propose a simple modification to TCP's - congestion control algorithms to decay the congestion window cwnd - after the transition from a sufficiently-long application-limited - period (i.e., at least one roundtrip time) to a network-limited - period. In particular, we propose that after an idle period, the TCP - sender should reduce its congestion window by half for every RTT that - the flow has remained idle. - - When the congestion window is reduced, the slow-start threshold - ssthresh remains as "memory" of the recent congestion window. - Specifically, ssthresh is never decreased when cwnd is reduced after - an application-limited period; before cwnd is reduced, ssthresh is - set to the maximum of its current value, and half-way between the old - and the new values of cwnd. This use of ssthresh allows a TCP sender - increasing its sending rate after an application-limited period to - quickly slow-start to recover most of the previous value of the - congestion window. To be more precise, if ssthresh is less than 3/4 - cwnd when the congestion window is reduced after an application- - limited period, then ssthresh is increased to 3/4 cwnd before the - reduction of the congestion window. - - An invalid congestion window also results when the congestion window - is increased (i.e., in TCP's slow-start or congestion avoidance - phases) during application-limited periods, when the previous value - of the congestion window might never have been fully utilized. As - far as we know, all current TCP implementations increase the - congestion window when an acknowledgement arrives, if allowed by the - receiver's advertised window and the slow-start or congestion - avoidance window increase algorithm, without checking to see if the - previous value of the congestion window has in fact been used. This - document proposes that the window increase algorithm not be invoked - during application-limited periods [MSML99]. In particular, the TCP - sender should not increase the congestion window when the TCP sender - has been application-limited (and therefore has not fully used the - current congestion window). This restriction prevents the congestion - window from growing arbitrarily large, in the absence of evidence - that the congestion window can be supported by the network. From - [MSML99, Section 5.2]: "This restriction assures that [cwnd] only - grows as long as TCP actually succeeds in injecting enough data into - the network to test the path." - - A somewhat-orthogonal problem associated with maintaining a large - congestion window after an application-limited period is that the - sender, with a sudden large amount of data to send after a quiescent - period, might immediately send a full congestion window of back-to- - back packets. This problem of sending large bursts of packets back- - to-back can be effectively handled using rate-based pacing (RBP, - - - -Handley, et al. Experimental [Page 3] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - [VH97]), or using a maximum burst size control [FF96]. We would - contend that, even with mechanisms for limiting the sending of back- - to-back packets or pacing packets out over the period of a roundtrip - time, an old congestion window that has not been fully used for some - time can not be trusted as an indication of the bandwidth currently - available for that flow. We would contend that the mechanisms to - pace out packets allowed by the congestion window are largely - orthogonal to the algorithms used to determine the appropriate size - of the congestion window. - -3. Description - - When a TCP sender has sufficient data available to fill the available - network capacity for that flow, cwnd and ssthresh get set to - appropriate values for the network conditions. When a TCP sender - stops sending, the flow stops sampling the network conditions, and so - the value of the congestion window may become inaccurate. We believe - the correct conservative behavior under these circumstances is to - decay the congestion window by half for every RTT that the flow - remains inactive. The value of half is a very conservative figure - based on how quickly multiplicative decrease would have decayed the - window in the presence of loss. - - Another possibility is that the sender may not stop sending, but may - become application-limited rather than network-limited, and offer - less data to the network than the congestion window allows to be - sent. In this case the TCP flow is still sampling network - conditions, but is not offering sufficient traffic to be sure that - there is still sufficient capacity in the network for that flow to - send a full congestion window. Under these circumstances we believe - the correct conservative behavior is for the sender to keep track of - the maximum amount of the congestion window used during each RTT, and - to decay the congestion window each RTT to midway between the current - cwnd value and the maximum value used. - - Before the congestion window is reduced, ssthresh is set to the - maximum of its current value and 3/4 cwnd. If the sender then has - more data to send than the decayed cwnd allows, the TCP will slow- - start (perform exponential increase) at least half-way back up to the - old value of cwnd. - - The justification for this value of "3/4 cwnd" is that 3/4 cwnd is a - conservative estimate of the recent average value of the congestion - window, and the TCP should safely be able to slow-start at least up - to this point. For a TCP in steady-state that has been reducing its - congestion window each time the congestion window reached some - maximum value `maxwin', the average congestion window has been 3/4 - maxwin. On average, when the connection becomes application-limited, - - - -Handley, et al. Experimental [Page 4] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - cwnd will be 3/4 maxwin, and in this case cwnd itself represents the - average value of the congestion window. However, if the connection - happens to become application-limited when cwnd equals maxwin, then - the average value of the congestion window is given by 3/4 cwnd. - - An alternate possibility would be to set ssthresh to the maximum of - the current value of ssthresh, and the old value of cwnd, allowing - TCP to slow-start all of the way back up to the old value of cwnd. - Further experimentation can be used to evaluate these two options for - setting ssthresh. - - For the separate issue of the increase of the congestion window in - response to an acknowledgement, we believe the correct behavior is - for the sender to increase the congestion window only if the window - was full when the acknowledgment arrived. - - We term this set of modifications to TCP Congestion Window Validation - (CWV) because they are related to ensuring the congestion window is - always a valid reflection of the current network state as probed by - the connection. - -3.1. The basic algorithm for reducing the congestion window - - A key issue in the CWV algorithm is to determine how to apply the - guideline of reducing the congestion window once for every roundtrip - time that the flow is application-limited. We use TCP's - retransmission timer (RTO) as a reasonable upper bound on the - roundtrip time, and reduce the congestion window roughly once per - RTO. - - This basic algorithm could be implemented in TCP as follows: When TCP - sends a new packet it checks to see if more than RTO seconds have - elapsed since the previous packet was sent. If RTO has elapsed, - ssthresh is set to the maximum of 3/4 cwnd and the current value of - ssthresh, and then the congestion window is halved for every RTO that - elapsed since the previous packet was sent. In addition, T_prev is - set to the current time, and W_used is reset to zero. T_prev will be - used to determine the elapsed time since the sender last was network- - limited or had reduced cwnd after an idle period. When the sender is - application-limited, W_used holds the maximum congestion window - actually used since the sender was last network-limited. - - The mechanism for determining the number of RTOs in the most recent - idle period could also be implemented by using a timer that expires - every RTO after the last packet was sent instead of a check per - packet - efficiency constraints on different operating systems may - dictate which is more efficient to implement. - - - - -Handley, et al. Experimental [Page 5] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - After TCP sends a packet, it also checks to see if that packet filled - the congestion window. If so, the sender is network-limited, and - sets the variable T_prev to the current TCP clock time, and the - variable W_used to zero. - - When TCP sends a packet that does not fill the congestion window, and - the TCP send queue is empty, then the sender is application-limited. - The sender checks to see if the amount of unacknowledged data is - greater than W_used; if so, W_used is set to the amount of - unacknowledged data. In addition TCP checks to see if the elapsed - time since T_prev is greater than RTO. If so, then the TCP has not - just reduced its congestion window following an idle period. The TCP - has been application-limited rather than network-limited for at least - an entire RTO interval, but for less than two RTO intervals. In this - case, TCP sets ssthresh to the maximum of 3/4 cwnd and the current - value of ssthresh, and reduces its congestion window to - (cwnd+W_used)/2. W_used is then set to zero, and T_prev is set to - the current time, so a further reduction will not take place until at - least another RTO period has elapsed. Thus, during an application- - limited period the CWV algorithm reduces the congestion window once - per RTO. - -3.2. Pseudo-code for reducing the congestion window - - Initially: - T_last = tcpnow, T_prev = tcpnow, W_used = 0 - - After sending a data segment: - If tcpnow - T_last >= RTO - (The sender has been idle.) - ssthresh = max(ssthresh, 3*cwnd/4) - For i=1 To (tcpnow - T_last)/RTO - win = min(cwnd, receiver's declared max window) - cwnd = max(win/2, MSS) - T_prev = tcpnow - W_used = 0 - - T_last = tcpnow - - If window is full - T_prev = tcpnow - W_used = 0 - Else - If no more data is available to send - W_used = max(W_used, amount of unacknowledged data) - If tcpnow - T_prev >= RTO - (The sender has been application-limited.) - ssthresh = max(ssthresh, 3*cwnd/4) - - - -Handley, et al. Experimental [Page 6] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - win = min(cwnd, receiver's declared max window) - cwnd = (win + W_used)/2 - T_prev = tcpnow - W_used = 0 - -4. Simulations - - The CWV proposal has been implemented as an option in the network - simulator NS [NS]. The simulations in the validation test suite for - CWV can be run with the command "./test-all-tcp" in the directory - "tcl/test". The simulations show the use of CWV to reduce the - congestion window after a period when the TCP connection was - application-limited, and to limit the increase in the congestion - window when a transfer is application-limited. As the simulations - illustrate, the use of ssthresh to maintain connection history is a - critical part of the Congestion Window Validation algorithm. [HPF99] - discusses these simulations in more detail. - -5. Experiments - - We have implemented the CWV mechanism in the TCP implementation in - FreeBSD 3.2. [HPF99] discusses these experiments in more detail. - - The first experiment examines the effects of the Congestion Window - Validation mechanisms for limiting cwnd increases during - application-limited periods. The experiment used a real ssh - connection through a modem link emulated using Dummynet [Dummynet]. - The link speed is 30Kb/s and the link has five packet buffers - available. Today most modem banks have more buffering available than - this, but the more buffer-limited situation sometimes occurs with - older modems. In the first half of the transfer, the user is typing - away over the connection. About half way through the time, the user - lists a moderately large file, which causes a large burst of traffic - to be transmitted. - - For the unmodified TCP, every returning ACK during the first part of - the transfer results in an increase in cwnd. As a result, the large - burst of data arriving from the application to the transport layer is - sent as many back-to-back packets, most of which get lost and - subsequently retransmitted. - - For the modified TCP with Congestion Window Validation, the - congestion window is not increased when the window is not full, and - has been decreased during application-limited periods closer to what - the user actually used. The burst of traffic is now constrained by - the congestion window, resulting in a better-behaved flow with - - - - - -Handley, et al. Experimental [Page 7] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - minimal loss. The end result is that the transfer happens - approximately 30% faster than the transfer without CWV, due to - avoiding retransmission timeouts. - - The second experiment uses a real ssh connection over a real dialup - ppp connection, where the modem bank has much more buffering. For - the unmodified TCP, the initial burst from the large file does not - cause loss, but does cause the RTT to increase to approximately 5 - seconds, where the connection becomes bounded by the receiver's - window. - - For the modified TCP with Congestion Window Validation, the flow is - much better behaved, and produces no large burst of traffic. In this - case the linear increase for cwnd results in a slow increase in the - RTT as the buffer slowly fills. - - For the second experiment, both the modified and the unmodified TCP - finish delivering the data at precisely the same time. This is - because the link has been fully utilized in both cases due to the - modem buffer being larger than the receiver window. Clearly a modem - buffer of this size is undesirable due to its effect on the RTT of - competing flows, but it is necessary with current TCP implementations - that produce bursts similar to those shown in the top graph. - -6. Conclusions - - This document has presented several TCP algorithms for Congestion - Window Validation, to be employed after an idle period or a period in - which the sender was application-limited, and before an increase of - the congestion window. The goal of these algorithms is for TCP's - congestion window to reflect recent knowledge of the TCP connection - about the state of the network path, while at the same time keeping - some memory (i.e., in ssthresh) about the earlier state of the path. - We believe that these modifications will be of benefit to both the - network and to the TCP flows themselves, by preventing unnecessary - packet drops due to the TCP sender's failure to update its - information (or lack of information) about current network - conditions. Future work will document and investigate the benefit - provided by these algorithms, using both simulations and experiments. - Additional future work will describe a more complex version of the - CWV algorithm for TCP implementations where the sender does not have - an accurate estimate of the TCP roundtrip time. - - - - - - - - - -Handley, et al. Experimental [Page 8] - -RFC 2861 TCP Congestion Window Validation June 2000 - - -7. References - - [FF96] Fall, K., and Floyd, S., Simulation-based Comparisons of - Tahoe, Reno, and SACK TCP, Computer Communication Review, - V. 26 N. 3, July 1996, pp. 5-21. URL - "http://www.aciri.org/floyd/papers.html". - - [HPF99] Mark Handley, Jitendra Padhye, Sally Floyd, TCP Congestion - Window Validation, UMass CMPSCI Technical Report 99-77, - September 1999. URL "ftp://www- - net.cs.umass.edu/pub/Handley99-tcpq-tr-99-77.ps.gz". - - [HTH98] Amy Hughes, Joe Touch, John Heidemann, "Issues in TCP - Slow-Start Restart After Idle", Work in Progress. - - [J88] Jacobson, V., Congestion Avoidance and Control, Originally - from Proceedings of SIGCOMM '88 (Palo Alto, CA, Aug. - 1988), and revised in 1992. URL "http://www- - nrg.ee.lbl.gov/nrg-papers.html". - - [JKBFL96] Raj Jain, Shiv Kalyanaraman, Rohit Goyal, Sonia Fahmy, and - Fang Lu, Comments on "Use-it or Lose-it", ATM Forum - Document Number: ATM Forum/96-0178, URL - "http://www.netlab.ohio- - state.edu/~jain/atmf/af_rl5b2.htm". - - [JKGFL95] R. Jain, S. Kalyanaraman, R. Goyal, S. Fahmy, and F. Lu, A - Fix for Source End System Rule 5, AF-TM 95-1660, December - 1995, URL "http://www.netlab.ohio- - state.edu/~jain/atmf/af_rl52.htm". - - [MSML99] Matt Mathis, Jeff Semke, Jamshid Mahdavi, and Kevin Lahey, - The Rate-Halving Algorithm for TCP Congestion Control, - June 1999. URL - "http://www.psc.edu/networking/ftp/papers/draft- - ratehalving.txt". - - [NS] NS, the UCB/LBNL/VINT Network Simulator. URL - "http://www-mash.cs.berkeley.edu/ns/". - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, TCP Congestion - Control, RFC 2581, April 1999. - - [VH97] Vikram Visweswaraiah and John Heidemann. Improving Restart - of Idle TCP Connections, Technical Report 97-661, - University of Southern California, November, 1997. - - - - - -Handley, et al. Experimental [Page 9] - -RFC 2861 TCP Congestion Window Validation June 2000 - - - [Dummynet] Luigi Rizzo, "Dummynet and Forward Error Correction", - Freenix 98, June 1998, New Orleans. URL - "http://info.iet.unipi.it/~luigi/ip_dummynet/". - -8. Security Considerations - - General security considerations concerning TCP congestion control are - discussed in RFC 2581. This document describes a algorithm for one - aspect of those congestion control procedures, and so the - considerations described in RFC 2581 apply to this algorithm also. - There are no known additional security concerns for this specific - algorithm. - -9. Authors' Addresses - - Mark Handley - AT&T Center for Internet Research at ICSI (ACIRI) - - Phone: +1 510 666 2946 - EMail: mjh@aciri.org - URL: http://www.aciri.org/mjh/ - - - Jitendra Padhye - AT&T Center for Internet Research at ICSI (ACIRI) - - Phone: +1 510 666 2887 - EMail: padhye@aciri.org - URL: http://www-net.cs.umass.edu/~jitu/ - - - Sally Floyd - AT&T Center for Internet Research at ICSI (ACIRI) - - Phone: +1 510 666 2989 - EMail: floyd@aciri.org - URL: http://www.aciri.org/floyd/ - - - - - - - - - - - - - - -Handley, et al. Experimental [Page 10] - -RFC 2861 TCP Congestion Window Validation June 2000 - - -10. Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Handley, et al. Experimental [Page 11] - diff --git a/ext/picotcp/RFC/rfc2873.txt b/ext/picotcp/RFC/rfc2873.txt deleted file mode 100644 index e81822c..0000000 --- a/ext/picotcp/RFC/rfc2873.txt +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - -Network Working Group X. Xiao -Request for Comments: 2873 Global Crossing -Category: Standards Track A. Hannan - iVMG - V. Paxson - ACIRI/ICSI - E. Crabbe - Exodus Communications - June 2000 - - - TCP Processing of the IPv4 Precedence Field - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - This memo describes a conflict between TCP [RFC793] and DiffServ - [RFC2475] on the use of the three leftmost bits in the TOS octet of - an IPv4 header [RFC791]. In a network that contains DiffServ-capable - nodes, such a conflict can cause failures in establishing TCP - connections or can cause some established TCP connections to be reset - undesirably. This memo proposes a modification to TCP for resolving - the conflict. - - Because the IPv6 [RFC2460] traffic class octet does not have any - defined meaning except what is defined in RFC 2474, and in particular - does not define precedence or security parameter bits, there is no - conflict between TCP and DiffServ on the use of any bits in the IPv6 - traffic class octet. - -1. Introduction - - In TCP, each connection has a set of states associated with it. Such - states are reflected by a set of variables stored in the TCP Control - Block (TCB) of both ends. Such variables may include the local and - remote socket number, precedence of the connection, security level - - - - -Xiao, et al. Standards Track [Page 1] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - - and compartment, etc. Both ends must agree on the setting of the - precedence and security parameters in order to establish a connection - and keep it open. - - There is no field in the TCP header that indicates the precedence of - a segment. Instead, the precedence field in the header of the IP - packet is used as the indication. The security level and compartment - are likewise carried in the IP header, but as IP options rather than - a fixed header field. Because of this difference, the problem with - precedence discussed in this memo does not apply to them. - - TCP requires that the precedence (and security parameters) of a - connection must remain unchanged during the lifetime of the - connection. Therefore, for an established TCP connection with - precedence, the receipt of a segment with different precedence - indicates an error. The connection must be reset [RFC793, pp. 36, 37, - 40, 66, 67, 71]. - - With the advent of DiffServ, intermediate nodes may modify the - Differentiated Services Codepoint (DSCP) [RFC2474] of the IP header - to indicate the desired Per-hop Behavior (PHB) [RFC2475, RFC2597, - RFC2598]. The DSCP includes the three bits formerly known as the - precedence field. Because any modification to those three bits will - be considered illegal by endpoints that are precedence-aware, they - may cause failures in establishing connections, or may cause - established connections to be reset. - -2. Terminology - - Segment: the unit of data that TCP sends to IP - - Precedence Field: the three leftmost bits in the TOS octet of an IPv4 - header. Note that in DiffServ, these three bits may or may not be - used to denote the precedence of the IP packet. There is no - precedence field in the traffic class octet in IPv6. - - TOS Field: bits 3-6 in the TOS octet of IPv4 header [RFC 1349]. - - MBZ field: Must Be Zero - - The structure of the TOS octet is depicted below: - - 0 1 2 3 4 5 6 7 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | PRECEDENCE | TOS | MBZ | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - - - - -Xiao, et al. Standards Track [Page 2] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - - DS Field: the TOS octet of an IPv4 header is renamed the - Differentiated Services (DS) Field by DiffServ. - - The structure of the DS field is depicted below: - - 0 1 2 3 4 5 6 7 - +---+---+---+---+---+---+---+---+ - | DSCP | CU | - +---+---+---+---+---+---+---+---+ - - DSCP: Differentiated Service Code Point, the leftmost 6 bits in the - DS field. - - CU: currently unused. - - Per-hop Behavior (PHB): a description of the externally observable - forwarding treatment applied at a differentiated services-compliant - node to a behavior aggregate. - -3. Problem Description - - The manipulation of the DSCP to achieve the desired PHB by DiffServ- - capable nodes may conflict with TCP's use of the precedence field. - This conflict can potentially cause problems for TCP implementations - that conform to RFC 793. First, page 36 of RFC 793 states: - - If the connection is in any non-synchronized state (LISTEN, SYN- - SENT, SYN-RECEIVED), and the incoming segment acknowledges - something not yet sent (the segment carries an unacceptable ACK), - or if an incoming segment has a security level or compartment - which does not exactly match the level and compartment requested - for the connection, a reset is sent. If our SYN has not been - acknowledged and the precedence level of the incoming segment is - higher than the precedence level requested then either raise the - local precedence level (if allowed by the user and the system) or - send a reset; or if the precedence level of the incoming segment - is lower than the precedence level requested then continue as if - the precedence matched exactly (if the remote TCP cannot raise - the precedence level to match ours this will be detected in the - next segment it sends, and the connection will be terminated - then). If our SYN has been acknowledged (perhaps in this incoming - segment) the precedence level of the incoming segment must match - the local precedence level exactly, if it does not a reset must - be sent. - - This leads to Problem #1: For a precedence-aware TCP module, if - during TCP's synchronization process, the precedence fields of the - SYN and/or ACK packets are modified by the intermediate nodes, - - - -Xiao, et al. Standards Track [Page 3] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - - resulting in the received ACK packet having a different precedence - from the precedence picked by this TCP module, the TCP connection - cannot be established, even if both modules actually agree on an - identical precedence for the connection. - - Then, on page 37, RFC 793 states: - - If the connection is in a synchronized state (ESTABLISHED, FIN- - WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT), - security level, or compartment, or precedence which does not - exactly match the level, and compartment, and precedence - requested for the connection, a reset is sent and connection goes - to the CLOSED state. - - This leads to Problem #2: For a precedence-aware TCP module, if the - precedence field of a received segment from an established TCP - connection has been changed en route by the intermediate nodes so as - to be different from the precedence specified during the connection - setup, the TCP connection will be reset. - - Each of problems #1 and #2 has a mirroring problem. They cause TCP - connections that must be reset according to RFC 793 not to be reset. - - Problem #3: A TCP connection may be established between two TCP - modules that pick different precedence, because the precedence fields - of the SYN and ACK packets are modified by intermediate nodes, - resulting in both modules thinking that they are in agreement for the - precedence of the connection. - - Problem #4: A TCP connection has been established normally by two - TCP modules that pick the same precedence. But in the middle of the - data transmission, one of the TCP modules changes the precedence of - its segments. According to RFC 793, the TCP connection must be reset. - In a DiffServ-capable environment, if the precedence of the segments - is altered by intermediate nodes such that it retains the expected - value when arriving at the other TCP module, the connection will not - be reset. - -4. Proposed Modification to TCP - - The proposed modification to TCP is that TCP must ignore the - precedence of all received segments. More specifically: - - (1) In TCP's synchronization process, the TCP modules at both ends - must ignore the precedence fields of the SYN and SYN ACK packets. The - TCP connection will be established if all the conditions specified by - RFC 793 are satisfied except the precedence of the connection. - - - - -Xiao, et al. Standards Track [Page 4] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - - (2) After a connection is established, each end sends segments with - its desired precedence. The precedence picked by one end of the TCP - connection may be the same or may be different from the precedence - picked by the other end (because precedence is ignored during - connection setup time). The precedence fields may be changed by the - intermediate nodes too. In either case, the precedence of the - received packets will be ignored by the other end. The TCP connection - will not be reset in either case. - - Problems #1 and #2 are solved by this proposed modification. Problems - #3 and #4 become non-issues because TCP must ignore the precedence. - In a DiffServ-capable environment, the two cases described in - problems #3 and #4 should be allowed. - -5. Security Considerations - - A TCP implementation that terminates a connection upon receipt of any - segment with an incorrect precedence field, regardless of the - correctness of the sequence numbers in the segment's header, poses a - serious denial-of-service threat, as all an attacker must do to - terminate a connection is guess the port numbers and then send two - segments with different precedence values; one of them is certain to - terminate the connection. Accordingly, the change to TCP processing - proposed in this memo would yield a significant gain in terms of that - TCP implementation's resilience. - - On the other hand, the stricter processing rules of RFC 793 in - principle make TCP spoofing attacks more difficult, as the attacker - must not only guess the victim TCP's initial sequence number, but - also its precedence setting. - - Finally, the security issues of each PHB group are addressed in the - PHB group's specification [RFC2597, RFC2598]. - -6. Acknowledgments - - Our thanks to Al Smith for his careful review and comments. - - - - - - - - - - - - - - -Xiao, et al. Standards Track [Page 5] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - -7. References - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, September - 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC1349] Almquist, P., "Type of Service in the Internet Protocol - Suite", RFC 1349, July 1992. - - [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC2474] Nichols, K., Blake, S., Baker, F. and D. Black, "Definition - of the Differentiated Services Field (DS Field) in the IPv4 - and IPv6 Headers", RFC 2474, December 1998. - - [RFC2475] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z. and - W. Weiss, "An Architecture for Differentiated Services", - RFC 2475, December 1998. - - [RFC2597] Heinanen, J., Baker, F., Weiss, W. and J. Wroclawski, - "Assured Forwarding PHB Group", RFC 2587, June 1999. - - [RFC2598] Jacobson, V., Nichols, K. and K. Poduri, "An Expedited - Forwarding PHB", RFC 2598, June 1999. - - - - - - - - - - - - - - - - - - - - - - - - -Xiao, et al. Standards Track [Page 6] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - -8. Authors' Addresses - - Xipeng Xiao - Global Crossing - 141 Caspian Court - Sunnyvale, CA 94089 - USA - - Phone: +1 408-543-4801 - EMail: xipeng@gblx.net - - - Alan Hannan - iVMG, Inc. - 112 Falkirk Court - Sunnyvale, CA 94087 - USA - - Phone: +1 408-749-7084 - EMail: alan@ivmg.net - - - Edward Crabbe - Exodus Communications - 2650 San Tomas Expressway - Santa Clara, CA 95051 - USA - - Phone: +1 408-346-1544 - EMail: edc@explosive.net - - - Vern Paxson - ACIRI/ICSI - 1947 Center Street - Suite 600 - Berkeley, CA 94704-1198 - USA - - Phone: +1 510-666-2882 - EMail: vern@aciri.org - - - - - - - - - - -Xiao, et al. Standards Track [Page 7] - -RFC 2873 TCP and the IPv4 Precedence Field June 2000 - - -9. Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Xiao, et al. Standards Track [Page 8] - diff --git a/ext/picotcp/RFC/rfc2883.txt b/ext/picotcp/RFC/rfc2883.txt deleted file mode 100644 index da6b6ab..0000000 --- a/ext/picotcp/RFC/rfc2883.txt +++ /dev/null @@ -1,955 +0,0 @@ - - - - - - -Network Working Group S. Floyd -Request for Comments: 2883 ACIRI -Category: Standards Track J. Mahdavi - Novell - M. Mathis - Pittsburgh Supercomputing Center - M. Podolsky - UC Berkeley - July 2000 - - - An Extension to the Selective Acknowledgement (SACK) Option for TCP - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - This note defines an extension of the Selective Acknowledgement - (SACK) Option [RFC2018] for TCP. RFC 2018 specified the use of the - SACK option for acknowledging out-of-sequence data not covered by - TCP's cumulative acknowledgement field. This note extends RFC 2018 - by specifying the use of the SACK option for acknowledging duplicate - packets. This note suggests that when duplicate packets are - received, the first block of the SACK option field can be used to - report the sequence numbers of the packet that triggered the - acknowledgement. This extension to the SACK option allows the TCP - sender to infer the order of packets received at the receiver, - allowing the sender to infer when it has unnecessarily retransmitted - a packet. A TCP sender could then use this information for more - robust operation in an environment of reordered packets [BPS99], ACK - loss, packet replication, and/or early retransmit timeouts. - -1. Conventions and Acronyms - - The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, - SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this - document, are to be interpreted as described in [B97]. - - - - -Floyd, et al. Standards Track [Page 1] - -RFC 2883 SACK Extension July 2000 - - -2. Introduction - - The Selective Acknowledgement (SACK) option defined in RFC 2018 is - used by the TCP data receiver to acknowledge non-contiguous blocks of - data not covered by the Cumulative Acknowledgement field. However, - RFC 2018 does not specify the use of the SACK option when duplicate - segments are received. This note specifies the use of the SACK - option when acknowledging the receipt of a duplicate packet [F99]. - We use the term D-SACK (for duplicate-SACK) to refer to a SACK block - that reports a duplicate segment. - - This document does not make any changes to TCP's use of the - cumulative acknowledgement field, or to the TCP receiver's decision - of *when* to send an acknowledgement packet. This document only - concerns the contents of the SACK option when an acknowledgement is - sent. - - This extension is compatible with current implementations of the SACK - option in TCP. That is, if one of the TCP end-nodes does not - implement this D-SACK extension and the other TCP end-node does, we - believe that this use of the D-SACK extension by one of the end nodes - will not introduce problems. - - The use of D-SACK does not require separate negotiation between a TCP - sender and receiver that have already negotiated SACK capability. - The absence of separate negotiation for D-SACK means that the TCP - receiver could send D-SACK blocks when the TCP sender does not - understand this extension to SACK. In this case, the TCP sender will - simply discard any D-SACK blocks, and process the other SACK blocks - in the SACK option field as it normally would. - - - - - - - - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 2] - -RFC 2883 SACK Extension July 2000 - - -3. The Sack Option Format as defined in RFC 2018 - - The SACK option as defined in RFC 2018 is as follows: - - +--------+--------+ - | Kind=5 | Length | - +--------+--------+--------+--------+ - | Left Edge of 1st Block | - +--------+--------+--------+--------+ - | Right Edge of 1st Block | - +--------+--------+--------+--------+ - | | - / . . . / - | | - +--------+--------+--------+--------+ - | Left Edge of nth Block | - +--------+--------+--------+--------+ - | Right Edge of nth Block | - +--------+--------+--------+--------+ - - The Selective Acknowledgement (SACK) option in the TCP header - contains a number of SACK blocks, where each block specifies the left - and right edge of a block of data received at the TCP receiver. In - particular, a block represents a contiguous sequence space of data - received and queued at the receiver, where the "left edge" of the - block is the first sequence number of the block, and the "right edge" - is the sequence number immediately following the last sequence number - of the block. - - RFC 2018 implies that the first SACK block specify the segment that - triggered the acknowledgement. From RFC 2018, when the data receiver - chooses to send a SACK option, "the first SACK block ... MUST specify - the contiguous block of data containing the segment which triggered - this ACK, unless that segment advanced the Acknowledgment Number - field in the header." - - However, RFC 2018 does not address the use of the SACK option when - acknowledging a duplicate segment. For example, RFC 2018 specifies - that "each block represents received bytes of data that are - contiguous and isolated". RFC 2018 further specifies that "if sent - at all, SACK options SHOULD be included in all ACKs which do not ACK - the highest sequence number in the data receiver's queue." RFC 2018 - does not specify the use of the SACK option when a duplicate segment - is received, and the cumulative acknowledgement field in the ACK - acknowledges all of the data in the data receiver's queue. - - - - - - -Floyd, et al. Standards Track [Page 3] - -RFC 2883 SACK Extension July 2000 - - -4. Use of the SACK option for reporting a duplicate segment - - This section specifies the use of SACK blocks when the SACK option is - used in reporting a duplicate segment. When D-SACK is used, the - first block of the SACK option should be a D-SACK block specifying - the sequence numbers for the duplicate segment that triggers the - acknowledgement. If the duplicate segment is part of a larger block - of non-contiguous data in the receiver's data queue, then the - following SACK block should be used to specify this larger block. - Additional SACK blocks can be used to specify additional non- - contiguous blocks of data, as specified in RFC 2018. - - The guidelines for reporting duplicate segments are summarized below: - - (1) A D-SACK block is only used to report a duplicate contiguous - sequence of data received by the receiver in the most recent packet. - - (2) Each duplicate contiguous sequence of data received is reported - in at most one D-SACK block. (I.e., the receiver sends two identical - D-SACK blocks in subsequent packets only if the receiver receives two - duplicate segments.) - - (3) The left edge of the D-SACK block specifies the first sequence - number of the duplicate contiguous sequence, and the right edge of - the D-SACK block specifies the sequence number immediately following - the last sequence in the duplicate contiguous sequence. - - (4) If the D-SACK block reports a duplicate contiguous sequence from - a (possibly larger) block of data in the receiver's data queue above - the cumulative acknowledgement, then the second SACK block in that - SACK option should specify that (possibly larger) block of data. - - (5) Following the SACK blocks described above for reporting duplicate - segments, additional SACK blocks can be used for reporting additional - blocks of data, as specified in RFC 2018. - - Note that because each duplicate segment is reported in only one ACK - packet, information about that duplicate segment will be lost if that - ACK packet is dropped in the network. - -4.1 Reporting Full Duplicate Segments - - We illustrate these guidelines with three examples. In each example, - we assume that the data receiver has first received eight segments of - 500 bytes each, and has sent an acknowledgement with the cumulative - acknowledgement field set to 4000 (assuming the first sequence number - is zero). The D-SACK block is underlined in each example. - - - - -Floyd, et al. Standards Track [Page 4] - -RFC 2883 SACK Extension July 2000 - - -4.1.1. Example 1: Reporting a duplicate segment. - - Because several ACK packets are lost, the data sender retransmits - packet 3000-3499, and the data receiver subsequently receives a - duplicate segment with sequence numbers 3000-3499. The receiver - sends an acknowledgement with the cumulative acknowledgement field - set to 4000, and the first, D-SACK block specifying sequence numbers - 3000-3500. - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 3000-3499 3000-3499 3500 (ACK dropped) - 3500-3999 3500-3999 4000 (ACK dropped) - 3000-3499 3000-3499 4000, SACK=3000-3500 - --------- -4.1.2. Example 2: Reporting an out-of-order segment and a duplicate - segment. - - Following a lost data packet, the receiver receives an out-of-order - data segment, which triggers the SACK option as specified in RFC - 2018. Because of several lost ACK packets, the sender then - retransmits a data packet. The receiver receives the duplicate - packet, and reports it in the first, D-SACK block: - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 3000-3499 3000-3499 3500 (ACK dropped) - 3500-3999 3500-3999 4000 (ACK dropped) - 4000-4499 (data packet dropped) - 4500-4999 4500-4999 4000, SACK=4500-5000 (ACK dropped) - 3000-3499 3000-3499 4000, SACK=3000-3500, 4500-5000 - --------- - - - - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 5] - -RFC 2883 SACK Extension July 2000 - - -4.1.3. Example 3: Reporting a duplicate of an out-of-order segment. - - Because of a lost data packet, the receiver receives two out-of-order - segments. The receiver next receives a duplicate segment for one of - these out-of-order segments: - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 3500-3999 3500-3999 4000 - 4000-4499 (data packet dropped) - 4500-4999 4500-4999 4000, SACK=4500-5000 - 5000-5499 5000-5499 4000, SACK=4500-5500 - (duplicated packet) - 5000-5499 4000, SACK=5000-5500, 4500-5500 - --------- -4.2. Reporting Partial Duplicate Segments - - It may be possible that a sender transmits a packet that includes one - or more duplicate sub-segments--that is, only part but not all of the - transmitted packet has already arrived at the receiver. This can - occur when the size of the sender's transmitted segments increases, - which can occur when the PMTU increases in the middle of a TCP - session, for example. The guidelines in Section 4 above apply to - reporting partial as well as full duplicate segments. This section - gives examples of these guidelines when reporting partial duplicate - segments. - - When the SACK option is used for reporting partial duplicate - segments, the first D-SACK block reports the first duplicate sub- - segment. If the data packet being acknowledged contains multiple - partial duplicate sub-segments, then only the first such duplicate - sub-segment is reported in the SACK option. We illustrate this with - the examples below. - -4.2.1. Example 4: Reporting a single duplicate subsegment. - - The sender increases the packet size from 500 bytes to 1000 bytes. - The receiver subsequently receives a 1000-byte packet containing one - 500-byte subsegment that has already been received and one which has - not. The receiver reports only the already received subsegment using - a single D-SACK block. - - - - - - - - - -Floyd, et al. Standards Track [Page 6] - -RFC 2883 SACK Extension July 2000 - - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 500-999 1000 - 1000-1499 (delayed) - 1500-1999 (data packet dropped) - 2000-2499 2000-2499 1000, SACK=2000-2500 - 1000-2000 1000-1499 1500, SACK=2000-2500 - 1000-2000 2500, SACK=1000-1500 - --------- - -4.2.2. Example 5: Two non-contiguous duplicate subsegments covered by - the cumulative acknowledgement. - - After the sender increases its packet size from 500 bytes to 1500 - bytes, the receiver receives a packet containing two non-contiguous - duplicate 500-byte subsegments which are less than the cumulative - acknowledgement field. The receiver reports the first such duplicate - segment in a single D-SACK block. - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 500-999 1000 - 1000-1499 (delayed) - 1500-1999 (data packet dropped) - 2000-2499 (delayed) - 2500-2999 (data packet dropped) - 3000-3499 3000-3499 1000, SACK=3000-3500 - 1000-2499 1000-1499 1500, SACK=3000-3500 - 2000-2499 1500, SACK=2000-2500, 3000-3500 - 1000-2499 2500, SACK=1000-1500, 3000-3500 - --------- - -4.2.3. Example 6: Two non-contiguous duplicate subsegments not covered - by the cumulative acknowledgement. - - This example is similar to Example 5, except that after the sender - increases the packet size, the receiver receives a packet containing - two non-contiguous duplicate subsegments which are above the - cumulative acknowledgement field, rather than below. The first, D- - SACK block reports the first duplicate subsegment, and the second, - SACK block reports the larger block of non-contiguous data that it - belongs to. - - - - - - - -Floyd, et al. Standards Track [Page 7] - -RFC 2883 SACK Extension July 2000 - - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 500-999 1000 - 1000-1499 (data packet dropped) - 1500-1999 (delayed) - 2000-2499 (data packet dropped) - 2500-2999 (delayed) - 3000-3499 (data packet dropped) - 3500-3999 3500-3999 1000, SACK=3500-4000 - 1000-1499 (data packet dropped) - 1500-2999 1500-1999 1000, SACK=1500-2000, 3500-4000 - 2000-2499 1000, SACK=2000-2500, 1500-2000, - 3500-4000 - 1500-2999 1000, SACK=1500-2000, 1500-3000, - --------- - 3500-4000 - -4.3. Interaction Between D-SACK and PAWS - - RFC 1323 [RFC1323] specifies an algorithm for Protection Against - Wrapped Sequence Numbers (PAWS). PAWS gives a method for - distinguishing between sequence numbers for new data, and sequence - numbers from a previous cycle through the sequence number space. - Duplicate segments might be detected by PAWS as belonging to a - previous cycle through the sequence number space. - - RFC 1323 specifies that for such packets, the receiver should do the - following: - - Send an acknowledgement in reply as specified in RFC 793 page 69, - and drop the segment. - - Since PAWS still requires sending an ACK, there is no harmful - interaction between PAWS and the use of D-SACK. The D-SACK block can - be included in the SACK option of the ACK, as outlined in Section 4, - independently of the use of PAWS by the TCP receiver, and - independently of the determination by PAWS of the validity or - invalidity of the data segment. - - TCP senders receiving D-SACK blocks should be aware that a segment - reported as a duplicate segment could possibly have been from a prior - cycle through the sequence number space. This is independent of the - use of PAWS by the TCP data receiver. We do not anticipate that this - will present significant problems for senders using D-SACK - information. - - - - - -Floyd, et al. Standards Track [Page 8] - -RFC 2883 SACK Extension July 2000 - - -5. Detection of Duplicate Packets - - This extension to the SACK option enables the receiver to accurately - report the reception of duplicate data. Because each receipt of a - duplicate packet is reported in only one ACK packet, the loss of a - single ACK can prevent this information from reaching the sender. In - addition, we note that the sender can not necessarily trust the - receiver to send it accurate information [SCWA99]. - - In order for the sender to check that the first (D)SACK block of an - acknowledgement in fact acknowledges duplicate data, the sender - should compare the sequence space in the first SACK block to the - cumulative ACK which is carried IN THE SAME PACKET. If the SACK - sequence space is less than this cumulative ACK, it is an indication - that the segment identified by the SACK block has been received more - than once by the receiver. An implementation MUST NOT compare the - sequence space in the SACK block to the TCP state variable snd.una - (which carries the total cumulative ACK), as this may result in the - wrong conclusion if ACK packets are reordered. - - If the sequence space in the first SACK block is greater than the - cumulative ACK, then the sender next compares the sequence space in - the first SACK block with the sequence space in the second SACK - block, if there is one. This comparison can determine if the first - SACK block is reporting duplicate data that lies above the cumulative - ACK. - - TCP implementations which follow RFC 2581 [RFC2581] could see - duplicate packets in each of the following four situations. This - document does not specify what action a TCP implementation should - take in these cases. The extension to the SACK option simply enables - the sender to detect each of these cases. Note that these four - conditions are not an exhaustive list of possible cases for duplicate - packets, but are representative of the most common/likely cases. - Subsequent documents will describe experimental proposals for sender - responses to the detection of unnecessary retransmits due to - reordering, lost ACKS, or early retransmit timeouts. - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 9] - -RFC 2883 SACK Extension July 2000 - - -5.1. Replication by the network - - If a packet is replicated in the network, this extension to the SACK - option can identify this. For example: - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 500-999 1000 - 1000-1499 1000-1499 1500 - (replicated) - 1000-1499 1500, SACK=1000-1500 - --------- - - In this case, the second packet was replicated in the network. An - ACK containing a D-SACK block which is lower than its ACK field and - is not identical to a previously retransmitted segment is indicative - of a replication by the network. - - WITHOUT D-SACK: - - If D-SACK was not used and the last ACK was piggybacked on a data - packet, the sender would not know that a packet had been replicated - in the network. If D-SACK was not used and neither of the last two - ACKs was piggybacked on a data packet, then the sender could - reasonably infer that either some data packet *or* the final ACK - packet had been replicated in the network. The receipt of the D-SACK - packet gives the sender positive knowledge that this data packet was - replicated in the network (assuming that the receiver is not lying). - - RESEARCH ISSUES: - - The current SACK option already allows the sender to identify - duplicate ACKs that do not acknowledge new data, but the D-SACK - option gives the sender a stronger basis for inferring that a - duplicate ACK does not acknowledge new data. The knowledge that a - duplicate ACK does not acknowledge new data allows the sender to - refrain from using that duplicate ACKs to infer packet loss (e.g., - Fast Retransmit) or to send more data (e.g., Fast Recovery). - -5.2. False retransmit due to reordering - - If packets are reordered in the network such that a segment arrives - more than 3 packets out of order, TCP's Fast Retransmit algorithm - will retransmit the out-of-order packet. An example of this is shown - below: - - - - - -Floyd, et al. Standards Track [Page 10] - -RFC 2883 SACK Extension July 2000 - - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 500-999 1000 - 1000-1499 (delayed) - 1500-1999 1500-1999 1000, SACK=1500-2000 - 2000-2499 2000-2499 1000, SACK=1500-2500 - 2500-2999 2500-2999 1000, SACK=1500-3000 - 1000-1499 1000-1499 3000 - 1000-1499 3000, SACK=1000-1500 - --------- - - In this case, an ACK containing a SACK block which is lower than its - ACK field and identical to a previously retransmitted segment is - indicative of a significant reordering followed by a false - (unnecessary) retransmission. - - WITHOUT D-SACK: - - With the use of D-SACK illustrated above, the sender knows that - either the first transmission of segment 1000-1499 was delayed in the - network, or the first transmission of segment 1000-1499 was dropped - and the second transmission of segment 1000-1499 was duplicated. - Given that no other segments have been duplicated in the network, - this second option can be considered unlikely. - - Without the use of D-SACK, the sender would only know that either the - first transmission of segment 1000-1499 was delayed in the network, - or that either one of the data segments or the final ACK was - duplicated in the network. Thus, the use of D-SACK allows the sender - to more reliably infer that the first transmission of segment - 1000-1499 was not dropped. - - [AP99], [L99], and [LK00] note that the sender could unambiguously - detect an unnecessary retransmit with the use of the timestamp - option. [LK00] proposes a timestamp-based algorithm that minimizes - the penalty for an unnecessary retransmit. [AP99] proposes a - heuristic for detecting an unnecessary retransmit in an environment - with neither timestamps nor SACK. [L99] also proposes a two-bit - field as an alternate to the timestamp option for unambiguously - marking the first three retransmissions of a packet. A similar idea - was proposed in [ISO8073]. - - RESEARCH ISSUES: - - The use of D-SACK allows the sender to detect some cases (e.g., when - no ACK packets have been lost) when a a Fast Retransmit was due to - packet reordering instead of packet loss. This allows the TCP sender - - - -Floyd, et al. Standards Track [Page 11] - -RFC 2883 SACK Extension July 2000 - - - to adjust the duplicate acknowledgment threshold, to prevent such - unnecessary Fast Retransmits in the future. Coupled with this, when - the sender determines, after the fact, that it has made an - unnecessary window reduction, the sender has the option of "undoing" - that reduction in the congestion window by resetting ssthresh to the - value of the old congestion window, and slow-starting until the - congestion window has reached that point. - - Any proposal for "undoing" a reduction in the congestion window would - have to address the possibility that the TCP receiver could be lying - in its reports of received packets [SCWA99]. - -5.3. Retransmit Timeout Due to ACK Loss - - If an entire window of ACKs is lost, a timeout will result. An - example of this is given below: - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 500-999 1000 (ACK dropped) - 1000-1499 1000-1499 1500 (ACK dropped) - 1500-1999 1500-1999 2000 (ACK dropped) - 2000-2499 2000-2499 2500 (ACK dropped) - (timeout) - 500-999 500-999 2500, SACK=500-1000 - -------- - - In this case, all of the ACKs are dropped, resulting in a timeout. - This condition can be identified because the first ACK received - following the timeout carries a D-SACK block indicating duplicate - data was received. - - WITHOUT D-SACK: - - Without the use of D-SACK, the sender in this case would be unable to - decide that no data packets has been dropped. - - RESEARCH ISSUES: - - For a TCP that implements some form of ACK congestion control - [BPK97], this ability to distinguish between dropped data packets and - dropped ACK packets would be particularly useful. In this case, the - connection could implement congestion control for the return (ACK) - path independently from the congestion control on the forward (data) - path. - - - - - -Floyd, et al. Standards Track [Page 12] - -RFC 2883 SACK Extension July 2000 - - -5.4. Early Retransmit Timeout - - If the sender's RTO is too short, an early retransmission timeout can - occur when no packets have in fact been dropped in the network. An - example of this is given below: - - Transmitted Received ACK Sent - Segment Segment (Including SACK Blocks) - - 500-999 (delayed) - 1000-1499 (delayed) - 1500-1999 (delayed) - 2000-2499 (delayed) - (timeout) - 500-999 (delayed) - 500-999 1000 - 1000-1499 (delayed) - 1000-1499 1500 - ... - 1500-1999 2000 - 2000-2499 2500 - 500-999 2500, SACK=500-1000 - -------- - 1000-1499 2500, SACK=1000-1500 - --------- - ... - - In this case, the first packet is retransmitted following the - timeout. Subsequently, the original window of packets arrives at the - receiver, resulting in ACKs for these segments. Following this, the - retransmissions of these segments arrive, resulting in ACKs carrying - SACK blocks which identify the duplicate segments. - - This can be identified as an early retransmission timeout because the - ACK for byte 1000 is received after the timeout with no SACK - information, followed by an ACK which carries SACK information (500- - 999) indicating that the retransmitted segment had already been - received. - - WITHOUT D-SACK: - - If D-SACK was not used and one of the duplicate ACKs was piggybacked - on a data packet, the sender would not know how many duplicate - packets had been received. If D-SACK was not used and none of the - duplicate ACKs were piggybacked on a data packet, then the sender - would have sent N duplicate packets, for some N, and received N - duplicate ACKs. In this case, the sender could reasonably infer that - - - - -Floyd, et al. Standards Track [Page 13] - -RFC 2883 SACK Extension July 2000 - - - some data or ACK packet had been replicated in the network, or that - an early retransmission timeout had occurred (or that the receiver is - lying). - - RESEARCH ISSUES: - - After the sender determines that an unnecessary (i.e., early) - retransmit timeout has occurred, the sender could adjust parameters - for setting the RTO, to prevent more unnecessary retransmit timeouts. - Coupled with this, when the sender determines, after the fact, that - it has made an unnecessary window reduction, the sender has the - option of "undoing" that reduction in the congestion window. - -6. Security Considerations - - This document neither strengthens nor weakens TCP's current security - properties. - -7. Acknowledgements - - We would like to thank Mark Handley, Reiner Ludwig, and Venkat - Padmanabhan for conversations on these issues, and to thank Mark - Allman for helpful feedback on this document. - -8. References - - [AP99] Mark Allman and Vern Paxson, On Estimating End-to-End - Network Path Properties, SIGCOMM 99, August 1999. URL - "http://www.acm.org/sigcomm/sigcomm99/papers/session7- - 3.html". - - [BPS99] J.C.R. Bennett, C. Partridge, and N. Shectman, Packet - Reordering is Not Pathological Network Behavior, IEEE/ACM - Transactions on Networking, Vol. 7, No. 6, December 1999, - pp. 789-798. - - [BPK97] Hari Balakrishnan, Venkata Padmanabhan, and Randy H. Katz, - The Effects of Asymmetry on TCP Performance, Third ACM/IEEE - Mobicom Conference, Budapest, Hungary, Sep 1997. URL - "http://www.cs.berkeley.edu/~padmanab/ - index.html#Publications". - - [F99] Floyd, S., Re: TCP and out-of-order delivery, Message ID - <199902030027.QAA06775@owl.ee.lbl.gov> to the end-to-end- - interest mailing list, February 1999. URL - "http://www.aciri.org/floyd/notes/TCP_Feb99.email". - - - - - -Floyd, et al. Standards Track [Page 14] - -RFC 2883 SACK Extension July 2000 - - - [ISO8073] ISO/IEC, Information-processing systems - Open Systems - Interconnection - Connection Oriented Transport Protocol - Specification, Internation Standard ISO/IEC 8073, December - 1988. - - [L99] Reiner Ludwig, A Case for Flow Adaptive Wireless links, - Technical Report UCB//CSD-99-1053, May 1999. URL - "http://iceberg.cs.berkeley.edu/papers/Ludwig- - FlowAdaptive/". - - [LK00] Reiner Ludwig and Randy H. Katz, The Eifel Algorithm: - Making TCP Robust Against Spurious Retransmissions, SIGCOMM - Computer Communication Review, V. 30, N. 1, January 2000. - URL "http://www.acm.org/sigcomm/ccr/archive/ccr-toc/ccr- - toc-2000.html". - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions for - High Performance", RFC 1323, May 1992. - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, April 1996. - - [RFC2581] Allman, M., Paxson,V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [SCWA99] Stefan Savage, Neal Cardwell, David Wetherall, Tom - Anderson, TCP Congestion Control with a Misbehaving - Receiver, ACM Computer Communications Review, pp. 71-78, V. - 29, N. 5, October, 1999. URL - "http://www.acm.org/sigcomm/ccr/archive/ccr-toc/ccr-toc- - 99.html". - - - - - - - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 15] - -RFC 2883 SACK Extension July 2000 - - -Authors' Addresses - - Sally Floyd - AT&T Center for Internet Research at ICSI (ACIRI) - - Phone: +1 510-666-6989 - EMail: floyd@aciri.org - URL: http://www.aciri.org/floyd/ - - - Jamshid Mahdavi - Novell - - Phone: 1-408-967-3806 - EMail: mahdavi@novell.com - - - Matt Mathis - Pittsburgh Supercomputing Center - - Phone: 412 268-3319 - EMail: mathis@psc.edu - URL: http://www.psc.edu/~mathis/ - - - Matthew Podolsky - UC Berkeley Electrical Engineering & Computer Science Dept. - - Phone: 510-649-8914 - EMail: podolsky@eecs.berkeley.edu - URL: http://www.eecs.berkeley.edu/~podolsky - - - - - - - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 16] - -RFC 2883 SACK Extension July 2000 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 17] - diff --git a/ext/picotcp/RFC/rfc2884.txt b/ext/picotcp/RFC/rfc2884.txt deleted file mode 100644 index 1092157..0000000 --- a/ext/picotcp/RFC/rfc2884.txt +++ /dev/null @@ -1,1011 +0,0 @@ - - - - - - -Network Working Group J. Hadi Salim -Request for Comments: 2884 Nortel Networks -Category: Informational U. Ahmed - Carleton University - July 2000 - - - Performance Evaluation of Explicit Congestion Notification (ECN) - in IP Networks - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - This memo presents a performance study of the Explicit Congestion - Notification (ECN) mechanism in the TCP/IP protocol using our - implementation on the Linux Operating System. ECN is an end-to-end - congestion avoidance mechanism proposed by [6] and incorporated into - RFC 2481[7]. We study the behavior of ECN for both bulk and - transactional transfers. Our experiments show that there is - improvement in throughput over NON ECN (TCP employing any of Reno, - SACK/FACK or NewReno congestion control) in the case of bulk - transfers and substantial improvement for transactional transfers. - - A more complete pdf version of this document is available at: - http://www7.nortel.com:8080/CTL/ecnperf.pdf - - This memo in its current revision is missing a lot of the visual - representations and experimental results found in the pdf version. - -1. Introduction - - In current IP networks, congestion management is left to the - protocols running on top of IP. An IP router when congested simply - drops packets. TCP is the dominant transport protocol today [26]. - TCP infers that there is congestion in the network by detecting - packet drops (RFC 2581). Congestion control algorithms [11] [15] [21] - are then invoked to alleviate congestion. TCP initially sends at a - higher rate (slow start) until it detects a packet loss. A packet - loss is inferred by the receipt of 3 duplicate ACKs or detected by a - - - -Salim & Ahmed Informational [Page 1] - -RFC 2884 ECN in IP Networks July 2000 - - - timeout. The sending TCP then moves into a congestion avoidance state - where it carefully probes the network by sending at a slower rate - (which goes up until another packet loss is detected). Traditionally - a router reacts to congestion by dropping a packet in the absence of - buffer space. This is referred to as Tail Drop. This method has a - number of drawbacks (outlined in Section 2). These drawbacks coupled - with the limitations of end-to-end congestion control have led to - interest in introducing smarter congestion control mechanisms in - routers. One such mechanism is Random Early Detection (RED) [9] - which detects incipient congestion and implicitly signals the - oversubscribing flow to slow down by dropping its packets. A RED- - enabled router detects congestion before the buffer overflows, based - on a running average queue size, and drops packets probabilistically - before the queue actually fills up. The probability of dropping a new - arriving packet increases as the average queue size increases above a - low water mark minth, towards higher water mark maxth. When the - average queue size exceeds maxth all arriving packets are dropped. - - An extension to RED is to mark the IP header instead of dropping - packets (when the average queue size is between minth and maxth; - above maxth arriving packets are dropped as before). Cooperating end - systems would then use this as a signal that the network is congested - and slow down. This is known as Explicit Congestion Notification - (ECN). In this paper we study an ECN implementation on Linux for - both the router and the end systems in a live network. The memo is - organized as follows. In Section 2 we give an overview of queue - management in routers. Section 3 gives an overview of ECN and the - changes required at the router and the end hosts to support ECN. - Section 4 defines the experimental testbed and the terminologies used - throughout this memo. Section 5 introduces the experiments that are - carried out, outlines the results and presents an analysis of the - results obtained. Section 6 concludes the paper. - -2. Queue Management in routers - - TCP's congestion control and avoidance algorithms are necessary and - powerful but are not enough to provide good service in all - circumstances since they treat the network as a black box. Some sort - of control is required from the routers to complement the end system - congestion control mechanisms. More detailed analysis is contained in - [19]. Queue management algorithms traditionally manage the length of - packet queues in the router by dropping packets only when the buffer - overflows. A maximum length for each queue is configured. The router - will accept packets till this maximum size is exceeded, at which - point it will drop incoming packets. New packets are accepted when - buffer space allows. This technique is known as Tail Drop. This - method has served the Internet well for years, but has the several - drawbacks. Since all arriving packets (from all flows) are dropped - - - -Salim & Ahmed Informational [Page 2] - -RFC 2884 ECN in IP Networks July 2000 - - - when the buffer overflows, this interacts badly with the congestion - control mechanism of TCP. A cycle is formed with a burst of drops - after the maximum queue size is exceeded, followed by a period of - underutilization at the router as end systems back off. End systems - then increase their windows simultaneously up to a point where a - burst of drops happens again. This phenomenon is called Global - Synchronization. It leads to poor link utilization and lower overall - throughput [19] Another problem with Tail Drop is that a single - connection or a few flows could monopolize the queue space, in some - circumstances. This results in a lock out phenomenon leading to - synchronization or other timing effects [19]. Lastly, one of the - major drawbacks of Tail Drop is that queues remain full for long - periods of time. One of the major goals of queue management is to - reduce the steady state queue size[19]. Other queue management - techniques include random drop on full and drop front on full [13]. - -2.1. Active Queue Management - - Active queue management mechanisms detect congestion before the queue - overflows and provide an indication of this congestion to the end - nodes [7]. With this approach TCP does not have to rely only on - buffer overflow as the indication of congestion since notification - happens before serious congestion occurs. One such active management - technique is RED. - -2.1.1. Random Early Detection - - Random Early Detection (RED) [9] is a congestion avoidance mechanism - implemented in routers which works on the basis of active queue - management. RED addresses the shortcomings of Tail Drop. A RED - router signals incipient congestion to TCP by dropping packets - probabilistically before the queue runs out of buffer space. This - drop probability is dependent on a running average queue size to - avoid any bias against bursty traffic. A RED router randomly drops - arriving packets, with the result that the probability of dropping a - packet belonging to a particular flow is approximately proportional - to the flow's share of bandwidth. Thus, if the sender is using - relatively more bandwidth it gets penalized by having more of its - packets dropped. RED operates by maintaining two levels of - thresholds minimum (minth) and maximum (maxth). It drops a packet - probabilistically if and only if the average queue size lies between - the minth and maxth thresholds. If the average queue size is above - the maximum threshold, the arriving packet is always dropped. When - the average queue size is between the minimum and the maximum - threshold, each arriving packet is dropped with probability pa, where - pa is a function of the average queue size. As the average queue - length varies between minth and maxth, pa increases linearly towards - a configured maximum drop probability, maxp. Beyond maxth, the drop - - - -Salim & Ahmed Informational [Page 3] - -RFC 2884 ECN in IP Networks July 2000 - - - probability is 100%. Dropping packets in this way ensures that when - some subset of the source TCP packets get dropped and they invoke - congestion avoidance algorithms that will ease the congestion at the - gateway. Since the dropping is distributed across flows, the problem - of global synchronization is avoided. - -3. Explicit Congestion Notification - - Explicit Congestion Notification is an extension proposed to RED - which marks a packet instead of dropping it when the average queue - size is between minth and maxth [7]. Since ECN marks packets before - congestion actually occurs, this is useful for protocols like TCP - that are sensitive to even a single packet loss. Upon receipt of a - congestion marked packet, the TCP receiver informs the sender (in the - subsequent ACK) about incipient congestion which will in turn trigger - the congestion avoidance algorithm at the sender. ECN requires - support from both the router as well as the end hosts, i.e. the end - hosts TCP stack needs to be modified. Packets from flows that are not - ECN capable will continue to be dropped by RED (as was the case - before ECN). - -3.1. Changes at the router - - Router side support for ECN can be added by modifying current RED - implementations. For packets from ECN capable hosts, the router marks - the packets rather than dropping them (if the average queue size is - between minth and maxth). It is necessary that the router identifies - that a packet is ECN capable, and should only mark packets that are - from ECN capable hosts. This uses two bits in the IP header. The ECN - Capable Transport (ECT) bit is set by the sender end system if both - the end systems are ECN capable (for a unicast transport, only if - both end systems are ECN-capable). In TCP this is confirmed in the - pre-negotiation during the connection setup phase (explained in - Section 3.2). Packets encountering congestion are marked by the - router using the Congestion Experienced (CE) (if the average queue - size is between minth and maxth) on their way to the receiver end - system (from the sender end system), with a probability proportional - to the average queue size following the procedure used in RED - (RFC2309) routers. Bits 10 and 11 in the IPV6 header are proposed - respectively for the ECT and CE bits. Bits 6 and 7 of the IPV4 header - DSCP field are also specified for experimental purposes for the ECT - and CE bits respectively. - -3.2. Changes at the TCP Host side - - The proposal to add ECN to TCP specifies two new flags in the - reserved field of the TCP header. Bit 9 in the reserved field of the - TCP header is designated as the ECN-Echo (ECE) flag and Bit 8 is - - - -Salim & Ahmed Informational [Page 4] - -RFC 2884 ECN in IP Networks July 2000 - - - designated as the Congestion Window Reduced (CWR) flag. These two - bits are used both for the initializing phase in which the sender and - the receiver negotiate the capability and the desire to use ECN, as - well as for the subsequent actions to be taken in case there is - congestion experienced in the network during the established state. - - There are two main changes that need to be made to add ECN to TCP to - an end system and one extension to a router running RED. - - 1. In the connection setup phase, the source and destination TCPs - have to exchange information about their desire and/or capability to - use ECN. This is done by setting both the ECN-Echo flag and the CWR - flag in the SYN packet of the initial connection phase by the sender; - on receipt of this SYN packet, the receiver will set the ECN-Echo - flag in the SYN-ACK response. Once this agreement has been reached, - the sender will thereon set the ECT bit in the IP header of data - packets for that flow, to indicate to the network that it is capable - and willing to participate in ECN. The ECT bit is set on all packets - other than pure ACK's. - - 2. When a router has decided from its active queue management - mechanism, to drop or mark a packet, it checks the IP-ECT bit in the - packet header. It sets the CE bit in the IP header if the IP-ECT bit - is set. When such a packet reaches the receiver, the receiver - responds by setting the ECN-Echo flag (in the TCP header) in the next - outgoing ACK for the flow. The receiver will continue to do this in - subsequent ACKs until it receives from the sender an indication that - it (the sender) has responded to the congestion notification. - - 3. Upon receipt of this ACK, the sender triggers its congestion - avoidance algorithm by halving its congestion window, cwnd, and - updating its congestion window threshold value ssthresh. Once it has - taken these appropriate steps, the sender sets the CWR bit on the - next data outgoing packet to tell the receiver that it has reacted to - the (receiver's) notification of congestion. The receiver reacts to - the CWR by halting the sending of the congestion notifications (ECE) - to the sender if there is no new congestion in the network. - - Note that the sender reaction to the indication of congestion in the - network (when it receives an ACK packet that has the ECN-Echo flag - set) is equivalent to the Fast Retransmit/Recovery algorithm (when - there is a congestion loss) in NON-ECN-capable TCP i.e. the sender - halves the congestion window cwnd and reduces the slow start - threshold ssthresh. Fast Retransmit/Recovery is still available for - ECN capable stacks for responding to three duplicate acknowledgments. - - - - - - -Salim & Ahmed Informational [Page 5] - -RFC 2884 ECN in IP Networks July 2000 - - -4. Experimental setup - - For testing purposes we have added ECN to the Linux TCP/IP stack, - kernels version 2.0.32. 2.2.5, 2.3.43 (there were also earlier - revisions of 2.3 which were tested). The 2.0.32 implementation - conforms to RFC 2481 [7] for the end systems only. We have also - modified the code in the 2.1,2.2 and 2.3 cases for the router portion - as well as end system to conform to the RFC. An outdated version of - the 2.0 code is available at [18]. Note Linux version 2.0.32 - implements TCP Reno congestion control while kernels >= 2.2.0 default - to New Reno but will opt for a SACK/FACK combo when the remote end - understands SACK. Our initial tests were carried out with the 2.0 - kernel at the end system and 2.1 (pre 2.2) for the router part. The - majority of the test results here apply to the 2.0 tests. We did - repeat these tests on a different testbed (move from Pentium to - Pentium-II class machines)with faster machines for the 2.2 and 2.3 - kernels, so the comparisons on the 2.0 and 2.2/3 are not relative. - - We have updated this memo release to reflect the tests against SACK - and New Reno. - -4.1. Testbed setup - - ----- ---- - | ECN | | ECN | - | ON | | OFF | - data direction ---->> ----- ---- - | | - server | | - ---- ------ ------ | | - | | | R1 | | R2 | | | - | | -----| | ---- | | ---------------------- - ---- ------ ^ ------ | - ^ | - | ----- - congestion point ___| | C | - | | - ----- - - The figure above shows our test setup. - - All the physical links are 10Mbps ethernet. Using Class Based - Queuing (CBQ) [22], packets from the data server are constricted to a - 1.5Mbps pipe at the router R1. Data is always retrieved from the - server towards the clients labelled , "ECN ON", "ECN OFF", and "C". - Since the pipe from the server is 10Mbps, this creates congestion at - the exit from the router towards the clients for competing flows. The - machines labeled "ECN ON" and "ECN OFF" are running the same version - - - -Salim & Ahmed Informational [Page 6] - -RFC 2884 ECN in IP Networks July 2000 - - - of Linux and have exactly the same hardware configuration. The server - is always ECN capable (and can handle NON ECN flows as well using the - standard congestion algorithms). The machine labeled "C" is used to - create congestion in the network. Router R2 acts as a path-delay - controller. With it we adjust the RTT the clients see. Router R1 - has RED implemented in it and has capability for supporting ECN - flows. The path-delay router is a PC running the Nistnet [16] - package on a Linux platform. The latency of the link for the - experiments was set to be 20 millisecs. - -4.2. Validating the Implementation - - We spent time validating that the implementation was conformant to - the specification in RFC 2481. To do this, the popular tcpdump - sniffer [24] was modified to show the packets being marked. We - visually inspected tcpdump traces to validate the conformance to the - RFC under a lot of different scenarios. We also modified tcptrace - [25] in order to plot the marked packets for visualization and - analysis. - - Both tcpdump and tcptrace revealed that the implementation was - conformant to the RFC. - -4.3. Terminology used - - This section presents background terminology used in the next few - sections. - - * Congesting flows: These are TCP flows that are started in the - background so as to create congestion from R1 towards R2. We use the - laptop labeled "C" to introduce congesting flows. Note that "C" as is - the case with the other clients retrieves data from the server. - - * Low, Moderate and High congestion: For the case of low congestion - we start two congesting flows in the background, for moderate - congestion we start five congesting flows and for the case of high - congestion we start ten congesting flows in the background. - - * Competing flows: These are the flows that we are interested in. - They are either ECN TCP flows from/to "ECN ON" or NON ECN TCP flows - from/to "ECN OFF". - - * Maximum drop rate: This is the RED parameter that sets the maximum - probability of a packet being marked at the router. This corresponds - to maxp as explained in Section 2.1. - - - - - - -Salim & Ahmed Informational [Page 7] - -RFC 2884 ECN in IP Networks July 2000 - - - Our tests were repeated for varying levels of congestion with varying - maximum drop rates. The results are presented in the subsequent - sections. - - * Low, Medium and High drop probability: We use the term low - probability to mean a drop probability maxp of 0.02, medium - probability for 0.2 and high probability for 0.5. We also - experimented with drop probabilities of 0.05, 0.1 and 0.3. - - * Goodput: We define goodput as the effective data rate as observed - by the user, i.e., if we transmitted 4 data packets in which two of - them were retransmitted packets, the efficiency is 50% and the - resulting goodput is 2*packet size/time taken to transmit. - - * RED Region: When the router's average queue size is between minth - and maxth we denote that we are operating in the RED region. - -4.4. RED parameter selection - - In our initial testing we noticed that as we increase the number of - congesting flows the RED queue degenerates into a simple Tail Drop - queue. i.e. the average queue exceeds the maximum threshold most of - the times. Note that this phenomena has also been observed by [5] - who proposes a dynamic solution to alleviate it by adjusting the - packet dropping probability "maxp" based on the past history of the - average queue size. Hence, it is necessary that in the course of our - experiments the router operate in the RED region, i.e., we have to - make sure that the average queue is maintained between minth and - maxth. If this is not maintained, then the queue acts like a Tail - Drop queue and the advantages of ECN diminish. Our goal is to - validate ECN's benefits when used with RED at the router. To ensure - that we were operating in the RED region we monitored the average - queue size and the actual queue size in times of low, moderate and - high congestion and fine-tuned the RED parameters such that the - average queue zones around the RED region before running the - experiment proper. Our results are, therefore, not influenced by - operating in the wrong RED region. - -5. The Experiments - - We start by making sure that the background flows do not bias our - results by computing the fairness index [12] in Section 5.1. We - proceed to carry out the experiments for bulk transfer presenting the - results and analysis in Section 5.2. In Section 5.3 the results for - transactional transfers along with analysis is presented. More - details on the experimental results can be found in [27]. - - - - - -Salim & Ahmed Informational [Page 8] - -RFC 2884 ECN in IP Networks July 2000 - - -5.1. Fairness - - In the course of the experiments we wanted to make sure that our - choice of the type of background flows does not bias the results that - we collect. Hence we carried out some tests initially with both ECN - and NON ECN flows as the background flows. We repeated the - experiments for different drop probabilities and calculated the - fairness index [12]. We also noticed (when there were equal number - of ECN and NON ECN flows) that the number of packets dropped for the - NON ECN flows was equal to the number of packets marked for the ECN - flows, showing thereby that the RED algorithm was fair to both kind - of flows. - - Fairness index: The fairness index is a performance metric described - in [12]. Jain [12] postulates that the network is a multi-user - system, and derives a metric to see how fairly each user is treated. - He defines fairness as a function of the variability of throughput - across users. For a given set of user throughputs (x1, x2...xn), the - fairness index to the set is defined as follows: - - f(x1,x2,.....,xn) = square((sum[i=1..n]xi))/(n*sum[i=1..n]square(xi)) - - The fairness index always lies between 0 and 1. A value of 1 - indicates that all flows got exactly the same throughput. Each of - the tests was carried out 10 times to gain confidence in our results. - To compute the fairness index we used FTP to generate traffic. - - Experiment details: At time t = 0 we start 2 NON ECN FTP sessions in - the background to create congestion. At time t=20 seconds we start - two competing flows. We note the throughput of all the flows in the - network and calculate the fairness index. The experiment was carried - out for various maximum drop probabilities and for various congestion - levels. The same procedure is repeated with the background flows as - ECN. The fairness index was fairly constant in both the cases when - the background flows were ECN and NON ECN indicating that there was - no bias when the background flows were either ECN or NON ECN. - - Max Fairness Fairness - Drop With BG With BG - Prob flows ECN flows NON ECN - - 0.02 0.996888 0.991946 - 0.05 0.995987 0.988286 - 0.1 0.985403 0.989726 - 0.2 0.979368 0.983342 - - - - - - -Salim & Ahmed Informational [Page 9] - -RFC 2884 ECN in IP Networks July 2000 - - - With the observation that the nature of background flows does not - alter the results, we proceed by using the background flows as NON - ECN for the rest of the experiments. - -5.2. Bulk transfers - - The metric we chose for bulk transfer is end user throughput. - - Experiment Details: All TCP flows used are RENO TCP. For the case of - low congestion we start 2 FTP flows in the background at time 0. Then - after about 20 seconds we start the competing flows, one data - transfer to the ECN machine and the second to the NON ECN machine. - The size of the file used is 20MB. For the case of moderate - congestion we start 5 FTP flows in the background and for the case of - high congestion we start 10 FTP flows in the background. We repeat - the experiments for various maximum drop rates each repeated for a - number of sets. - - Observation and Analysis: - - We make three key observations: - - 1) As the congestion level increases, the relative advantage for ECN - increases but the absolute advantage decreases (expected, since there - are more flows competing for the same link resource). ECN still does - better than NON ECN even under high congestion. Infering a sample - from the collected results: at maximum drop probability of 0.1, for - example, the relative advantage of ECN increases from 23% to 50% as - the congestion level increases from low to high. - - 2) Maintaining congestion levels and varying the maximum drop - probability (MDP) reveals that the relative advantage of ECN - increases with increasing MDP. As an example, for the case of high - congestion as we vary the drop probability from 0.02 to 0.5 the - relative advantage of ECN increases from 10% to 60%. - - 3) There were hardly any retransmissions for ECN flows (except the - occasional packet drop in a minority of the tests for the case of - high congestion and low maximum drop probability). - - We analyzed tcpdump traces for NON ECN with the help of tcptrace and - observed that there were hardly any retransmits due to timeouts. - (Retransmit due to timeouts are inferred by counting the number of 3 - DUPACKS retransmit and subtracting them from the total recorded - number of retransmits). This means that over a long period of time - (as is the case of long bulk transfers), the data-driven loss - recovery mechanism of the Fast Retransmit/Recovery algorithm is very - effective. The algorithm for ECN on congestion notification from ECE - - - -Salim & Ahmed Informational [Page 10] - -RFC 2884 ECN in IP Networks July 2000 - - - is the same as that for a Fast Retransmit for NON ECN. Since both are - operating in the RED region, ECN barely gets any advantage over NON - ECN from the signaling (packet drop vs. marking). - - It is clear, however, from the results that ECN flows benefit in bulk - transfers. We believe that the main advantage of ECN for bulk - transfers is that less time is spent recovering (whereas NON ECN - spends time retransmitting), and timeouts are avoided altogether. - [23] has shown that even with RED deployed, TCP RENO could suffer - from multiple packet drops within the same window of data, likely to - lead to multiple congestion reactions or timeouts (these problems are - alleviated by ECN). However, while TCP Reno has performance problems - with multiple packets dropped in a window of data, New Reno and SACK - have no such problems. - - Thus, for scenarios with very high levels of congestion, the - advantages of ECN for TCP Reno flows could be more dramatic than the - advantages of ECN for NewReno or SACK flows. An important - observation to make from our results is that we do not notice - multiple drops within a single window of data. Thus, we would expect - that our results are not heavily influenced by Reno's performance - problems with multiple packets dropped from a window of data. We - repeated these tests with ECN patched newer Linux kernels. As - mentioned earlier these kernels would use a SACK/FACK combo with a - fallback to New Reno. SACK can be selectively turned off (defaulting - to New Reno). Our results indicate that ECN still improves - performance for the bulk transfers. More results are available in the - pdf version[27]. As in 1) above, maintaining a maximum drop - probability of 0.1 and increasing the congestion level, it is - observed that ECN-SACK improves performance from about 5% at low - congestion to about 15% at high congestion. In the scenario where - high congestion is maintained and the maximum drop probability is - moved from 0.02 to 0.5, the relative advantage of ECN-SACK improves - from 10% to 40%. Although this numbers are lower than the ones - exhibited by Reno, they do reflect the improvement that ECN offers - even in the presence of robust recovery mechanisms such as SACK. - -5.3. Transactional transfers - - We model transactional transfers by sending a small request and - getting a response from a server before sending the next request. To - generate transactional transfer traffic we use Netperf [17] with the - CRR (Connect Request Response) option. As an example let us assume - that we are retrieving a small file of say 5 - 20 KB, then in effect - we send a small request to the server and the server responds by - sending us the file. The transaction is complete when we receive the - complete file. To gain confidence in our results we carry the - simulation for about one hour. For each test there are a few thousand - - - -Salim & Ahmed Informational [Page 11] - -RFC 2884 ECN in IP Networks July 2000 - - - of these requests and responses taking place. Although not exactly - modeling HTTP 1.0 traffic, where several concurrent sessions are - opened, Netperf-CRR is nevertheless a close approximation. Since - Netperf-CRR waits for one connection to complete before opening the - next one (0 think time), that single connection could be viewed as - the slowest response in the set of the opened concurrent sessions (in - HTTP). The transactional data sizes were selected based on [2] which - indicates that the average web transaction was around 8 - 10 KB; The - smaller (5KB) size was selected to guestimate the size of - transactional processing that may become prevalent with policy - management schemes in the diffserv [4] context. Using Netperf we are - able to initiate these kind of transactional transfers for a variable - length of time. The main metric of interest in this case is the - transaction rate, which is recorded by Netperf. - - * Define Transaction rate as: The number of requests and complete - responses for a particular requested size that we are able to do per - second. For example if our request is of 1KB and the response is 5KB - then we define the transaction rate as the number of such complete - transactions that we can accomplish per second. - - Experiment Details: Similar to the case of bulk transfers we start - the background FTP flows to introduce the congestion in the network - at time 0. About 20 seconds later we start the transactional - transfers and run each test for three minutes. We record the - transactions per second that are complete. We repeat the test for - about an hour and plot the various transactions per second, averaged - out over the runs. The experiment is repeated for various maximum - drop probabilities, file sizes and various levels of congestion. - - Observation and Analysis - - There are three key observations: - - 1) As congestion increases (with fixed drop probability) the relative - advantage for ECN increases (again the absolute advantage does not - increase since more flows are sharing the same bandwidth). For - example, from the results, if we consider the 5KB transactional flow, - as we increase the congestion from medium congestion (5 congesting - flows) to high congestion (10 congesting flows) for a maximum drop - probability of 0.1 the relative gain for ECN increases from 42% to - 62%. - - 2) Maintaining the congestion level while adjusting the maximum drop - probability indicates that the relative advantage for ECN flows - increase. From the case of high congestion for the 5KB flow we - - - - - -Salim & Ahmed Informational [Page 12] - -RFC 2884 ECN in IP Networks July 2000 - - - observe that the number of transactions per second increases from 0.8 - to 2.2 which corresponds to an increase in relative gain for ECN of - 20% to 140%. - - 3) As the transactional data size increases, ECN's advantage - diminishes because the probability of recovering from a Fast - Retransmit increases for NON ECN. ECN, therefore, has a huge - advantage as the transactional data size gets smaller as is observed - in the results. This can be explained by looking at TCP recovery - mechanisms. NON ECN in the short flows depends, for recovery, on - congestion signaling via receiving 3 duplicate ACKs, or worse by a - retransmit timer expiration, whereas ECN depends mostly on the TCP- - ECE flag. This is by design in our experimental setup. [3] shows - that most of the TCP loss recovery in fact happens in timeouts for - short flows. The effectiveness of the Fast Retransmit/Recovery - algorithm is limited by the fact that there might not be enough data - in the pipe to elicit 3 duplicate ACKs. TCP RENO needs at least 4 - outstanding packets to recover from losses without going into a - timeout. For 5KB (4 packets for MTU of 1500Bytes) a NON ECN flow will - always have to wait for a retransmit timeout if any of its packets - are lost. ( This timeout could only have been avoided if the flow had - used an initial window of four packets, and the first of the four - packets was the packet dropped). We repeated these experiments with - the kernels implementing SACK/FACK and New Reno algorithms. Our - observation was that there was hardly any difference with what we saw - with Reno. For example in the case of SACK-ECN enabling: maintaining - the maximum drop probability to 0.1 and increasing the congestion - level for the 5KB transaction we noticed that the relative gain for - the ECN enabled flows increases from 47-80%. If we maintain the - congestion level for the 5KB transactions and increase the maximum - drop probabilities instead, we notice that SACKs performance - increases from 15%-120%. It is fair to comment that the difference - in the testbeds (different machines, same topology) might have - contributed to the results; however, it is worth noting that the - relative advantage of the SACK-ECN is obvious. - -6. Conclusion - - ECN enhancements improve on both bulk and transactional TCP traffic. - The improvement is more obvious in short transactional type of flows - (popularly referred to as mice). - - * Because less retransmits happen with ECN, it means less traffic on - the network. Although the relative amount of data retransmitted in - our case is small, the effect could be higher when there are more - contributing end systems. The absence of retransmits also implies an - improvement in the goodput. This becomes very important for scenarios - - - - -Salim & Ahmed Informational [Page 13] - -RFC 2884 ECN in IP Networks July 2000 - - - where bandwidth is expensive such as in low bandwidth links. This - implies also that ECN lends itself well to applications that require - reliability but would prefer to avoid unnecessary retransmissions. - - * The fact that ECN avoids timeouts by getting faster notification - (as opposed to traditional packet dropping inference from 3 duplicate - ACKs or, even worse, timeouts) implies less time is spent during - error recovery - this also improves goodput. - - * ECN could be used to help in service differentiation where the end - user is able to "probe" for their target rate faster. Assured - forwarding [1] in the diffserv working group at the IETF proposes - using RED with varying drop probabilities as a service - differentiation mechanism. It is possible that multiple packets - within a single window in TCP RENO could be dropped even in the - presence of RED, likely leading into timeouts [23]. ECN end systems - ignore multiple notifications, which help in countering this scenario - resulting in improved goodput. The ECN end system also ends up - probing the network faster (to reach an optimal bandwidth). [23] also - notes that RENO is the most widely deployed TCP implementation today. - - It is clear that the advent of policy management schemes introduces - new requirements for transactional type of applications, which - constitute a very short query and a response in the order of a few - packets. ECN provides advantages to transactional traffic as we have - shown in the experiments. - -7. Acknowledgements - - We would like to thank Alan Chapman, Ioannis Lambadaris, Thomas Kunz, - Biswajit Nandy, Nabil Seddigh, Sally Floyd, and Rupinder Makkar for - their helpful feedback and valuable suggestions. - -8. Security Considerations - - Security considerations are as discussed in section 9 of RFC 2481. - -9. References - - [1] Heinanen, J., Finland, T., Baker, F., Weiss, W. and J. - Wroclawski, "Assured Forwarding PHB Group", RFC 2597, June 1999. - - [2] B.A. Mat. "An empirical model of HTTP network traffic." In - proceedings INFOCOMM'97. - - - - - - - -Salim & Ahmed Informational [Page 14] - -RFC 2884 ECN in IP Networks July 2000 - - - [3] Balakrishnan H., Padmanabhan V., Seshan S., Stemn M. and Randy - H. Katz, "TCP Behavior of a busy Internet Server: Analysis and - Improvements", Proceedings of IEEE Infocom, San Francisco, CA, - USA, March '98 - http://nms.lcs.mit.edu/~hari/papers/infocom98.ps.gz - - [4] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z. and W. - Weiss, "An Architecture for Differentiated Services", RFC 2475, - December 1998. - - [5] W. Feng, D. Kandlur, D. Saha, K. Shin, "Techniques for - Eliminating Packet Loss in Congested TCP/IP Networks", U. - Michigan CSE-TR-349-97, November 1997. - - [6] S. Floyd. "TCP and Explicit Congestion Notification." ACM - Computer Communications Review, 24, October 1994. - - [7] Ramakrishnan, K. and S. Floyd, "A Proposal to add Explicit - Congestion Notification (ECN) to IP", RFC 2481, January 1999. - - [8] Kevin Fall, Sally Floyd, "Comparisons of Tahoe, RENO and Sack - TCP", Computer Communications Review, V. 26 N. 3, July 1996, - pp. 5-21 - - [9] S. Floyd and V. Jacobson. "Random Early Detection Gateways for - Congestion Avoidance". IEEE/ACM Transactions on Networking, - 3(1), August 1993. - - [10] E. Hashem. "Analysis of random drop for gateway congestion - control." Rep. Lcs tr-465, Lav. Fot Comput. Sci., M.I.T., 1989. - - [11] V. Jacobson. "Congestion Avoidance and Control." In Proceedings - of SIGCOMM '88, Stanford, CA, August 1988. - - [12] Raj Jain, "The art of computer systems performance analysis", - John Wiley and sons QA76.9.E94J32, 1991. - - [13] T. V. Lakshman, Arnie Neidhardt, Teunis Ott, "The Drop From - Front Strategy in TCP Over ATM and Its Interworking with Other - Control Features", Infocom 96, MA28.1. - - [14] P. Mishra and H. Kanakia. "A hop by hop rate based congestion - control scheme." Proc. SIGCOMM '92, pp. 112-123, August 1992. - - [15] Floyd, S. and T. Henderson, "The NewReno Modification to TCP's - Fast Recovery Algorithm", RFC 2582, April 1999. - - - - - -Salim & Ahmed Informational [Page 15] - -RFC 2884 ECN in IP Networks July 2000 - - - [16] The NIST Network Emulation Tool - http://www.antd.nist.gov/itg/nistnet/ - - [17] The network performance tool - http://www.netperf.org/netperf/NetperfPage.html - - [18] ftp://ftp.ee.lbl.gov/ECN/ECN-package.tgz - - [19] Braden, B., Clark, D., Crowcroft, J., Davie, B., Deering, S., - Estrin, D., Floyd, S., Jacobson, V., Minshall, G., Partridge, - C., Peterson, L., Ramakrishnan, K., Shenker, S., Wroclawski, J. - and L. Zhang, "Recommendations on Queue Management and - Congestion Avoidance in the Internet", RFC 2309, April 1998. - - [20] K. K. Ramakrishnan and R. Jain. "A Binary feedback scheme for - congestion avoidance in computer networks." ACM Trans. Comput. - Syst.,8(2):158-181, 1990. - - [21] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, October 1996. - - [22] S. Floyd and V. Jacobson, "Link sharing and Resource Management - Models for packet Networks", IEEE/ACM Transactions on - Networking, Vol. 3 No.4, August 1995. - - [23] Prasad Bagal, Shivkumar Kalyanaraman, Bob Packer, "Comparative - study of RED, ECN and TCP Rate Control". - http://www.packeteer.com/technology/Pdf/packeteer-final.pdf - - [24] tcpdump, the protocol packet capture & dumper program. - ftp://ftp.ee.lbl.gov/tcpdump.tar.Z - - [25] TCP dump file analysis tool: - http://jarok.cs.ohiou.edu/software/tcptrace/tcptrace.html - - [26] Thompson K., Miller, G.J., Wilder R., "Wide-Area Internet - Traffic Patterns and Characteristics". IEEE Networks Magazine, - November/December 1997. - - [27] http://www7.nortel.com:8080/CTL/ecnperf.pdf - - - - - - - - - - - -Salim & Ahmed Informational [Page 16] - -RFC 2884 ECN in IP Networks July 2000 - - -10. Authors' Addresses - - Jamal Hadi Salim - Nortel Networks - 3500 Carling Ave - Ottawa, ON, K2H 8E9 - Canada - - EMail: hadi@nortelnetworks.com - - - Uvaiz Ahmed - Dept. of Systems and Computer Engineering - Carleton University - Ottawa - Canada - - EMail: ahmed@sce.carleton.ca - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Salim & Ahmed Informational [Page 17] - -RFC 2884 ECN in IP Networks July 2000 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Salim & Ahmed Informational [Page 18] - diff --git a/ext/picotcp/RFC/rfc2914.txt b/ext/picotcp/RFC/rfc2914.txt deleted file mode 100644 index f48e1d3..0000000 --- a/ext/picotcp/RFC/rfc2914.txt +++ /dev/null @@ -1,955 +0,0 @@ - - - - - - -Network Working Group S. Floyd -Request for Comments: 2914 ACIRI -BCP: 41 September 2000 -Category: Best Current Practice - - - Congestion Control Principles - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - The goal of this document is to explain the need for congestion - control in the Internet, and to discuss what constitutes correct - congestion control. One specific goal is to illustrate the dangers - of neglecting to apply proper congestion control. A second goal is - to discuss the role of the IETF in standardizing new congestion - control protocols. - -1. Introduction - - This document draws heavily from earlier RFCs, in some cases - reproducing entire sections of the text of earlier documents - [RFC2309, RFC2357]. We have also borrowed heavily from earlier - publications addressing the need for end-to-end congestion control - [FF99]. - -2. Current standards on congestion control - - IETF standards concerning end-to-end congestion control focus either - on specific protocols (e.g., TCP [RFC2581], reliable multicast - protocols [RFC2357]) or on the syntax and semantics of communications - between the end nodes and routers about congestion information (e.g., - Explicit Congestion Notification [RFC2481]) or desired quality-of- - service (diff-serv)). The role of end-to-end congestion control is - also discussed in an Informational RFC on "Recommendations on Queue - Management and Congestion Avoidance in the Internet" [RFC2309]. RFC - 2309 recommends the deployment of active queue management mechanisms - in routers, and the continuation of design efforts towards mechanisms - - - - -Floyd, ed. Best Current Practice [Page 1] - -RFC 2914 Congestion Control Principles September 2000 - - - in routers to deal with flows that are unresponsive to congestion - notification. We freely borrow from RFC 2309 some of their general - discussion of end-to-end congestion control. - - In contrast to the RFCs discussed above, this document is a more - general discussion of the principles of congestion control. One of - the keys to the success of the Internet has been the congestion - avoidance mechanisms of TCP. While TCP is still the dominant - transport protocol in the Internet, it is not ubiquitous, and there - are an increasing number of applications that, for one reason or - another, choose not to use TCP. Such traffic includes not only - multicast traffic, but unicast traffic such as streaming multimedia - that does not require reliability; and traffic such as DNS or routing - messages that consist of short transfers deemed critical to the - operation of the network. Much of this traffic does not use any form - of either bandwidth reservations or end-to-end congestion control. - The continued use of end-to-end congestion control by best-effort - traffic is critical for maintaining the stability of the Internet. - - This document also discusses the general role of the IETF in the - standardization of new congestion control protocols. - - The discussion of congestion control principles for differentiated - services or integrated services is not addressed in this document. - Some categories of integrated or differentiated services include a - guarantee by the network of end-to-end bandwidth, and as such do not - require end-to-end congestion control mechanisms. - -3. The development of end-to-end congestion control. - -3.1. Preventing congestion collapse. - - The Internet protocol architecture is based on a connectionless end- - to-end packet service using the IP protocol. The advantages of its - connectionless design, flexibility and robustness, have been amply - demonstrated. However, these advantages are not without cost: - careful design is required to provide good service under heavy load. - In fact, lack of attention to the dynamics of packet forwarding can - result in severe service degradation or "Internet meltdown". This - phenomenon was first observed during the early growth phase of the - Internet of the mid 1980s [RFC896], and is technically called - "congestion collapse". - - The original specification of TCP [RFC793] included window-based flow - control as a means for the receiver to govern the amount of data sent - by the sender. This flow control was used to prevent overflow of the - receiver's data buffer space available for that connection. [RFC793] - - - - -Floyd, ed. Best Current Practice [Page 2] - -RFC 2914 Congestion Control Principles September 2000 - - - reported that segments could be lost due either to errors or to - network congestion, but did not include dynamic adjustment of the - flow-control window in response to congestion. - - The original fix for Internet meltdown was provided by Van Jacobson. - Beginning in 1986, Jacobson developed the congestion avoidance - mechanisms that are now required in TCP implementations [Jacobson88, - RFC 2581]. These mechanisms operate in the hosts to cause TCP - connections to "back off" during congestion. We say that TCP flows - are "responsive" to congestion signals (i.e., dropped packets) from - the network. It is these TCP congestion avoidance algorithms that - prevent the congestion collapse of today's Internet. - - However, that is not the end of the story. Considerable research has - been done on Internet dynamics since 1988, and the Internet has - grown. It has become clear that the TCP congestion avoidance - mechanisms [RFC2581], while necessary and powerful, are not - sufficient to provide good service in all circumstances. In addition - to the development of new congestion control mechanisms [RFC2357], - router-based mechanisms are in development that complement the - endpoint congestion avoidance mechanisms. - - A major issue that still needs to be addressed is the potential for - future congestion collapse of the Internet due to flows that do not - use responsible end-to-end congestion control. RFC 896 [RFC896] - suggested in 1984 that gateways should detect and `squelch' - misbehaving hosts: "Failure to respond to an ICMP Source Quench - message, though, should be regarded as grounds for action by a - gateway to disconnect a host. Detecting such failure is non-trivial - but is a worthwhile area for further research." Current papers - still propose that routers detect and penalize flows that are not - employing acceptable end-to-end congestion control [FF99]. - -3.2. Fairness - - In addition to a concern about congestion collapse, there is a - concern about `fairness' for best-effort traffic. Because TCP "backs - off" during congestion, a large number of TCP connections can share a - single, congested link in such a way that bandwidth is shared - reasonably equitably among similarly situated flows. The equitable - sharing of bandwidth among flows depends on the fact that all flows - are running compatible congestion control algorithms. For TCP, this - means congestion control algorithms conformant with the current TCP - specification [RFC793, RFC1122, RFC2581]. - - The issue of fairness among competing flows has become increasingly - important for several reasons. First, using window scaling - [RFC1323], individual TCPs can use high bandwidth even over high- - - - -Floyd, ed. Best Current Practice [Page 3] - -RFC 2914 Congestion Control Principles September 2000 - - - propagation-delay paths. Second, with the growth of the web, - Internet users increasingly want high-bandwidth and low-delay - communications, rather than the leisurely transfer of a long file in - the background. The growth of best-effort traffic that does not use - TCP underscores this concern about fairness between competing best- - effort traffic in times of congestion. - - The popularity of the Internet has caused a proliferation in the - number of TCP implementations. Some of these may fail to implement - the TCP congestion avoidance mechanisms correctly because of poor - implementation [RFC2525]. Others may deliberately be implemented - with congestion avoidance algorithms that are more aggressive in - their use of bandwidth than other TCP implementations; this would - allow a vendor to claim to have a "faster TCP". The logical - consequence of such implementations would be a spiral of increasingly - aggressive TCP implementations, or increasingly aggressive transport - protocols, leading back to the point where there is effectively no - congestion avoidance and the Internet is chronically congested. - - There is a well-known way to achieve more aggressive performance - without even changing the transport protocol, by changing the level - of granularity: open multiple connections to the same place, as has - been done in the past by some Web browsers. Thus, instead of a - spiral of increasingly aggressive transport protocols, we would - instead have a spiral of increasingly aggressive web browsers, or - increasingly aggressive applications. - - This raises the issue of the appropriate granularity of a "flow", - where we define a `flow' as the level of granularity appropriate for - the application of both fairness and congestion control. From RFC - 2309: "There are a few `natural' answers: 1) a TCP or UDP connection - (source address/port, destination address/port); 2) a - source/destination host pair; 3) a given source host or a given - destination host. We would guess that the source/destination host - pair gives the most appropriate granularity in many circumstances. - The granularity of flows for congestion management is, at least in - part, a policy question that needs to be addressed in the wider IETF - community." - - Again borrowing from RFC 2309, we use the term "TCP-compatible" for a - flow that behaves under congestion like a flow produced by a - conformant TCP. A TCP-compatible flow is responsive to congestion - notification, and in steady-state uses no more bandwidth than a - conformant TCP running under comparable conditions (drop rate, RTT, - MTU, etc.) - - - - - - -Floyd, ed. Best Current Practice [Page 4] - -RFC 2914 Congestion Control Principles September 2000 - - - It is convenient to divide flows into three classes: (1) TCP- - compatible flows, (2) unresponsive flows, i.e., flows that do not - slow down when congestion occurs, and (3) flows that are responsive - but are not TCP-compatible. The last two classes contain more - aggressive flows that pose significant threats to Internet - performance, as we discuss below. - - In addition to steady-state fairness, the fairness of the initial - slow-start is also a concern. One concern is the transient effect on - other flows of a flow with an overly-aggressive slow-start procedure. - Slow-start performance is particularly important for the many flows - that are short-lived, and only have a small amount of data to - transfer. - -3.3. Optimizing performance regarding throughput, delay, and loss. - - In addition to the prevention of congestion collapse and concerns - about fairness, a third reason for a flow to use end-to-end - congestion control can be to optimize its own performance regarding - throughput, delay, and loss. In some circumstances, for example in - environments of high statistical multiplexing, the delay and loss - rate experienced by a flow are largely independent of its own sending - rate. However, in environments with lower levels of statistical - multiplexing or with per-flow scheduling, the delay and loss rate - experienced by a flow is in part a function of the flow's own sending - rate. Thus, a flow can use end-to-end congestion control to limit - the delay or loss experienced by its own packets. We would note, - however, that in an environment like the current best-effort - Internet, concerns regarding congestion collapse and fairness with - competing flows limit the range of congestion control behaviors - available to a flow. - -4. The role of the standards process - - The standardization of a transport protocol includes not only - standardization of aspects of the protocol that could affect - interoperability (e.g., information exchanged by the end-nodes), but - also standardization of mechanisms deemed critical to performance - (e.g., in TCP, reduction of the congestion window in response to a - packet drop). At the same time, implementation-specific details and - other aspects of the transport protocol that do not affect - interoperability and do not significantly interfere with performance - do not require standardization. Areas of TCP that do not require - standardization include the details of TCP's Fast Recovery procedure - after a Fast Retransmit [RFC2582]. The appendix uses examples from - TCP to discuss in more detail the role of the standards process in - the development of congestion control. - - - - -Floyd, ed. Best Current Practice [Page 5] - -RFC 2914 Congestion Control Principles September 2000 - - -4.1. The development of new transport protocols. - - In addition to addressing the danger of congestion collapse, the - standardization process for new transport protocols takes care to - avoid a congestion control `arms race' among competing protocols. As - an example, in RFC 2357 [RFC2357] the TSV Area Directors and their - Directorate outline criteria for the publication as RFCs of - Internet-Drafts on reliable multicast transport protocols. From - [RFC2357]: "A particular concern for the IETF is the impact of - reliable multicast traffic on other traffic in the Internet in times - of congestion, in particular the effect of reliable multicast traffic - on competing TCP traffic.... The challenge to the IETF is to - encourage research and implementations of reliable multicast, and to - enable the needs of applications for reliable multicast to be met as - expeditiously as possible, while at the same time protecting the - Internet from the congestion disaster or collapse that could result - from the widespread use of applications with inappropriate reliable - multicast mechanisms." - - The list of technical criteria that must be addressed by RFCs on new - reliable multicast transport protocols include the following: "Is - there a congestion control mechanism? How well does it perform? When - does it fail? Note that congestion control mechanisms that operate - on the network more aggressively than TCP will face a great burden of - proof that they don't threaten network stability." - - It is reasonable to expect that these concerns about the effect of - new transport protocols on competing traffic will apply not only to - reliable multicast protocols, but to unreliable unicast, reliable - unicast, and unreliable multicast traffic as well. - -4.2. Application-level issues that affect congestion control - - The specific issue of a browser opening multiple connections to the - same destination has been addressed by RFC 2616 [RFC2616], which - states in Section 8.1.4 that "Clients that use persistent connections - SHOULD limit the number of simultaneous connections that they - maintain to a given server. A single-user client SHOULD NOT maintain - more than 2 connections with any server or proxy." - -4.3. New developments in the standards process - - The most obvious developments in the IETF that could affect the - evolution of congestion control are the development of integrated and - differentiated services [RFC2212, RFC2475] and of Explicit Congestion - Notification (ECN) [RFC2481]. However, other less dramatic - developments are likely to affect congestion control as well. - - - - -Floyd, ed. Best Current Practice [Page 6] - -RFC 2914 Congestion Control Principles September 2000 - - - One such effort is that to construct Endpoint Congestion Management - [BS00], to enable multiple concurrent flows from a sender to the same - receiver to share congestion control state. By allowing multiple - connections to the same destination to act as one flow in terms of - end-to-end congestion control, a Congestion Manager could allow - individual connections slow-starting to take advantage of previous - information about the congestion state of the end-to-end path. - Further, the use of a Congestion Manager could remove the congestion - control dangers of multiple flows being opened between the same - source/destination pair, and could perhaps be used to allow a browser - to open many simultaneous connections to the same destination. - -5. A description of congestion collapse - - This section discusses congestion collapse from undelivered packets - in some detail, and shows how unresponsive flows could contribute to - congestion collapse in the Internet. This section draws heavily on - material from [FF99]. - - Informally, congestion collapse occurs when an increase in the - network load results in a decrease in the useful work done by the - network. As discussed in Section 3, congestion collapse was first - reported in the mid 1980s [RFC896], and was largely due to TCP - connections unnecessarily retransmitting packets that were either in - transit or had already been received at the receiver. We call the - congestion collapse that results from the unnecessary retransmission - of packets classical congestion collapse. Classical congestion - collapse is a stable condition that can result in throughput that is - a small fraction of normal [RFC896]. Problems with classical - congestion collapse have generally been corrected by the timer - improvements and congestion control mechanisms in modern - implementations of TCP [Jacobson88]. - - A second form of potential congestion collapse occurs due to - undelivered packets. Congestion collapse from undelivered packets - arises when bandwidth is wasted by delivering packets through the - network that are dropped before reaching their ultimate destination. - This is probably the largest unresolved danger with respect to - congestion collapse in the Internet today. Different scenarios can - result in different degrees of congestion collapse, in terms of the - fraction of the congested links' bandwidth used for productive work. - The danger of congestion collapse from undelivered packets is due - primarily to the increasing deployment of open-loop applications not - using end-to-end congestion control. Even more destructive would be - best-effort applications that *increase* their sending rate in - response to an increased packet drop rate (e.g., automatically using - an increased level of FEC). - - - - -Floyd, ed. Best Current Practice [Page 7] - -RFC 2914 Congestion Control Principles September 2000 - - - Table 1 gives the results from a scenario with congestion collapse - from undelivered packets, where scarce bandwidth is wasted by packets - that never reach their destination. The simulation uses a scenario - with three TCP flows and one UDP flow competing over a congested 1.5 - Mbps link. The access links for all nodes are 10 Mbps, except that - the access link to the receiver of the UDP flow is 128 Kbps, only 9% - of the bandwidth of shared link. When the UDP source rate exceeds - 128 Kbps, most of the UDP packets will be dropped at the output port - to that final link. - - UDP - Arrival UDP TCP Total - Rate Goodput Goodput Goodput - -------------------------------------- - 0.7 0.7 98.5 99.2 - 1.8 1.7 97.3 99.1 - 2.6 2.6 96.0 98.6 - 5.3 5.2 92.7 97.9 - 8.8 8.4 87.1 95.5 - 10.5 8.4 84.8 93.2 - 13.1 8.4 81.4 89.8 - 17.5 8.4 77.3 85.7 - 26.3 8.4 64.5 72.8 - 52.6 8.4 38.1 46.4 - 58.4 8.4 32.8 41.2 - 65.7 8.4 28.5 36.8 - 75.1 8.4 19.7 28.1 - 87.6 8.4 11.3 19.7 - 105.2 8.4 3.4 11.8 - 131.5 8.4 2.4 10.7 - - Table 1. A simulation with three TCP flows and one UDP flow. - - Table 1 shows the UDP arrival rate from the sender, the UDP goodput - (defined as the bandwidth delivered to the receiver), the TCP goodput - (as delivered to the TCP receivers), and the aggregate goodput on the - congested 1.5 Mbps link. Each rate is given as a fraction of the - bandwidth of the congested link. As the UDP source rate increases, - the TCP goodput decreases roughly linearly, and the UDP goodput is - nearly constant. Thus, as the UDP flow increases its offered load, - its only effect is to hurt the TCP and aggregate goodput. On the - congested link, the UDP flow ultimately `wastes' the bandwidth that - could have been used by the TCP flow, and reduces the goodput in the - network as a whole down to a small fraction of the bandwidth of the - congested link. - - - - - - -Floyd, ed. Best Current Practice [Page 8] - -RFC 2914 Congestion Control Principles September 2000 - - - The simulations in Table 1 illustrate both unfairness and congestion - collapse. As [FF99] discusses, compatible congestion control is not - the only way to provide fairness; per-flow scheduling at the - congested routers is an alternative mechanism at the routers that - guarantees fairness. However, as discussed in [FF99], per-flow - scheduling can not be relied upon to prevent congestion collapse. - - There are only two alternatives for eliminating the danger of - congestion collapse from undelivered packets. The first alternative - for preventing congestion collapse from undelivered packets is the - use of effective end-to-end congestion control by the end nodes. - More specifically, the requirement would be that a flow avoid a - pattern of significant losses at links downstream from the first - congested link on the path. (Here, we would consider any link a - `congested link' if any flow is using bandwidth that would otherwise - be used by other traffic on the link.) Given that an end-node is - generally unable to distinguish between a path with one congested - link and a path with multiple congested links, the most reliable way - for a flow to avoid a pattern of significant losses at a downstream - congested link is for the flow to use end-to-end congestion control, - and reduce its sending rate in the presence of loss. - - A second alternative for preventing congestion collapse from - undelivered packets would be a guarantee by the network that packets - accepted at a congested link in the network will be delivered all the - way to the receiver [RFC2212, RFC2475]. We note that the choice - between the first alternative of end-to-end congestion control and - the second alternative of end-to-end bandwidth guarantees does not - have to be an either/or decision; congestion collapse can be - prevented by the use of effective end-to-end congestion by some of - the traffic, and the use of end-to-end bandwidth guarantees from the - network for the rest of the traffic. - -6. Forms of end-to-end congestion control - - This document has discussed concerns about congestion collapse and - about fairness with TCP for new forms of congestion control. This - does not mean, however, that concerns about congestion collapse and - fairness with TCP necessitate that all best-effort traffic deploy - congestion control based on TCP's Additive-Increase Multiplicative- - Decrease (AIMD) algorithm of reducing the sending rate in half in - response to each packet drop. This section separately discusses the - implications of these two concerns of congestion collapse and - fairness with TCP. - - - - - - - -Floyd, ed. Best Current Practice [Page 9] - -RFC 2914 Congestion Control Principles September 2000 - - -6.1. End-to-end congestion control for avoiding congestion collapse. - - The avoidance of congestion collapse from undelivered packets - requires that flows avoid a scenario of a high sending rate, multiple - congested links, and a persistent high packet drop rate at the - downstream link. Because congestion collapse from undelivered - packets consists of packets that waste valuable bandwidth only to be - dropped downstream, this form of congestion collapse is not possible - in an environment where each flow traverses only one congested link, - or where only a small number of packets are dropped at links - downstream of the first congested link. Thus, any form of congestion - control that successfully avoids a high sending rate in the presence - of a high packet drop rate should be sufficient to avoid congestion - collapse from undelivered packets. - - We would note that the addition of Explicit Congestion Notification - (ECN) to the IP architecture would not, in and of itself, remove the - danger of congestion collapse for best-effort traffic. ECN allows - routers to set a bit in packet headers as an indication of congestion - to the end-nodes, rather than being forced to rely on packet drops to - indicate congestion. However, with ECN, packet-marking would replace - packet-dropping only in times of moderate congestion. In particular, - when congestion is heavy, and a router's buffers overflow, the router - has no choice but to drop arriving packets. - -6.2. End-to-end congestion control for fairness with TCP. - - The concern expressed in [RFC2357] about fairness with TCP places a - significant though not crippling constraint on the range of viable - end-to-end congestion control mechanisms for best-effort traffic. An - environment with per-flow scheduling at all congested links would - isolate flows from each other, and eliminate the need for congestion - control mechanisms to be TCP-compatible. An environment with - differentiated services, where flows marked as belonging to a certain - diff-serv class would be scheduled in isolation from best-effort - traffic, could allow the emergence of an entire diff-serv class of - traffic where congestion control was not required to be TCP- - compatible. Similarly, a pricing-controlled environment, or a diff- - serv class with its own pricing paradigm, could supercede the concern - about fairness with TCP. However, for the current Internet - environment, where other best-effort traffic could compete in a FIFO - queue with TCP traffic, the absence of fairness with TCP could lead - to one flow `starving out' another flow in a time of high congestion, - as was illustrated in Table 1 above. - - However, the list of TCP-compatible congestion control procedures is - not limited to AIMD with the same increase/ decrease parameters as - TCP. Other TCP-compatible congestion control procedures include - - - -Floyd, ed. Best Current Practice [Page 10] - -RFC 2914 Congestion Control Principles September 2000 - - - rate-based variants of AIMD; AIMD with different sets of - increase/decrease parameters that give the same steady-state - behavior; equation-based congestion control where the sender adjusts - its sending rate in response to information about the long-term - packet drop rate; layered multicast where receivers subscribe and - unsubscribe from layered multicast groups; and possibly other forms - that we have not yet begun to consider. - -7. Acknowledgements - - Much of this document draws directly on previous RFCs addressing - end-to-end congestion control. This attempts to be a summary of - ideas that have been discussed for many years, and by many people. - In particular, acknowledgement is due to the members of the End-to- - End Research Group, the Reliable Multicast Research Group, and the - Transport Area Directorate. This document has also benefited from - discussion and feedback from the Transport Area Working Group. - Particular thanks are due to Mark Allman for feedback on an earlier - version of this document. - -8. References - - [BS00] Balakrishnan H. and S. Seshan, "The Congestion Manager", - Work in Progress. - - [DMKM00] Dawkins, S., Montenegro, G., Kojo, M. and V. Magret, - "End-to-end Performance Implications of Slow Links", - Work in Progress. - - [FF99] Floyd, S. and K. Fall, "Promoting the Use of End-to-End - Congestion Control in the Internet", IEEE/ACM - Transactions on Networking, August 1999. URL - http://www.aciri.org/floyd/end2end-paper.html - - [HPF00] Handley, M., Padhye, J. and S. Floyd, "TCP Congestion - Window Validation", RFC 2861, June 2000. - - [Jacobson88] V. Jacobson, Congestion Avoidance and Control, ACM - SIGCOMM '88, August 1988. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC896] Nagle, J., "Congestion Control in IP/TCP", RFC 896, - January 1984. - - [RFC1122] Braden, R., Ed., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - - -Floyd, ed. Best Current Practice [Page 11] - -RFC 2914 Congestion Control Principles September 2000 - - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2212] Shenker, S., Partridge, C. and R. Guerin, "Specification - of Guaranteed Quality of Service", RFC 2212, September - 1997. - - [RFC2309] Braden, R., Clark, D., Crowcroft, J., Davie, B., - Deering, S., Estrin, D., Floyd, S., Jacobson, V., - Minshall, G., Partridge, C., Peterson, L., Ramakrishnan, - K.K., Shenker, S., Wroclawski, J., and L. Zhang, - "Recommendations on Queue Management and Congestion - Avoidance in the Internet", RFC 2309, April 1998. - - [RFC2357] Mankin, A., Romanow, A., Bradner, S. and V. Paxson, - "IETF Criteria for Evaluating Reliable Multicast - Transport and Application Protocols", RFC 2357, June - 1998. - - [RFC2414] Allman, M., Floyd, S. and C. Partridge, "Increasing - TCP's Initial Window", RFC 2414, September 1998. - - [RFC2475] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z. - and W. Weiss, "An Architecture for Differentiated - Services", RFC 2475, December 1998. - - [RFC2481] Ramakrishnan K. and S. Floyd, "A Proposal to add - Explicit Congestion Notification (ECN) to IP", RFC 2481, - January 1999. - - [RFC2525] Paxson, V., Allman, M., Dawson, S., Fenner, W., Griner, - J., Heavens, I., Lahey, K., Semke, J. and B. Volz, - "Known TCP Implementation Problems", RFC 2525, March - 1999. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2582] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., - Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext - Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. - - - - -Floyd, ed. Best Current Practice [Page 12] - -RFC 2914 Congestion Control Principles September 2000 - - - [SCWA99] S. Savage, N. Cardwell, D. Wetherall, and T. Anderson, - TCP Congestion Control with a Misbehaving Receiver, ACM - Computer Communications Review, October 1999. - - [TCPB98] Hari Balakrishnan, Venkata N. Padmanabhan, Srinivasan - Seshan, Mark Stemm, and Randy H. Katz, TCP Behavior of a - Busy Internet Server: Analysis and Improvements, IEEE - Infocom, March 1998. Available from: - "http://www.cs.berkeley.edu/~hari/papers/infocom98.ps.gz". - - [TCPF98] Dong Lin and H.T. Kung, TCP Fast Recovery Strategies: - Analysis and Improvements, IEEE Infocom, March 1998. - Available from: - "http://www.eecs.harvard.edu/networking/papers/infocom- - tcp-final-198.pdf". - -9. TCP-Specific issues - - In this section we discuss some of the particulars of TCP congestion - control, to illustrate a realization of the congestion control - principles, including some of the details that arise when - incorporating them into a production transport protocol. - -9.1. Slow-start. - - The TCP sender can not open a new connection by sending a large burst - of data (e.g., a receiver's advertised window) all at once. The TCP - sender is limited by a small initial value for the congestion window. - During slow-start, the TCP sender can increase its sending rate by at - most a factor of two in one roundtrip time. Slow-start ends when - congestion is detected, or when the sender's congestion window is - greater than the slow-start threshold ssthresh. - - An issue that potentially affects global congestion control, and - therefore has been explicitly addressed in the standards process, - includes an increase in the value of the initial window - [RFC2414,RFC2581]. - - Issues that have not been addressed in the standards process, and are - generally considered not to require standardization, include such - issues as the use (or non-use) of rate-based pacing, and mechanisms - for ending slow-start early, before the congestion window reaches - ssthresh. Such mechanisms result in slow-start behavior that is as - conservative or more conservative than standard TCP. - - - - - - - -Floyd, ed. Best Current Practice [Page 13] - -RFC 2914 Congestion Control Principles September 2000 - - -9.2. Additive Increase, Multiplicative Decrease. - - In the absence of congestion, the TCP sender increases its congestion - window by at most one packet per roundtrip time. In response to a - congestion indication, the TCP sender decreases its congestion window - by half. (More precisely, the new congestion window is half of the - minimum of the congestion window and the receiver's advertised - window.) - - An issue that potentially affects global congestion control, and - therefore would be likely to be explicitly addressed in the standards - process, would include a proposed addition of congestion control for - the return stream of `pure acks'. - - An issue that has not been addressed in the standards process, and is - generally not considered to require standardization, would be a - change to the congestion window to apply as an upper bound on the - number of bytes presumed to be in the pipe, instead of applying as a - sliding window starting from the cumulative acknowledgement. - (Clearly, the receiver's advertised window applies as a sliding - window starting from the cumulative acknowledgement field, because - packets received above the cumulative acknowledgement field are held - in TCP's receive buffer, and have not been delivered to the - application. However, the congestion window applies to the number of - packets outstanding in the pipe, and does not necessarily have to - include packets that have been received out-of-order by the TCP - receiver.) - -9.3. Retransmit timers. - - The TCP sender sets a retransmit timer to infer that a packet has - been dropped in the network. When the retransmit timer expires, the - sender infers that a packet has been lost, sets ssthresh to half of - the current window, and goes into slow-start, retransmitting the lost - packet. If the retransmit timer expires because no acknowledgement - has been received for a retransmitted packet, the retransmit timer is - also "backed-off", doubling the value of the next retransmit timeout - interval. - - An issue that potentially affects global congestion control, and - therefore would be likely to be explicitly addressed in the standards - process, might include a modified mechanism for setting the - retransmit timer that could significantly increase the number of - retransmit timers that expire prematurely, when the acknowledgement - has not yet arrived at the sender, but in fact no packets have been - dropped. This could be of concern to the Internet standards process - - - - - -Floyd, ed. Best Current Practice [Page 14] - -RFC 2914 Congestion Control Principles September 2000 - - - because retransmit timers that expire prematurely could lead to an - increase in the number of packets unnecessarily transmitted on a - congested link. - -9.4. Fast Retransmit and Fast Recovery. - - After seeing three duplicate acknowledgements, the TCP sender infers - a packet loss. The TCP sender sets ssthresh to half of the current - window, reduces the congestion window to at most half of the previous - window, and retransmits the lost packet. - - An issue that potentially affects global congestion control, and - therefore would be likely to be explicitly addressed in the standards - process, might include a proposal (if there was one) for inferring a - lost packet after only one or two duplicate acknowledgements. If - poorly designed, such a proposal could lead to an increase in the - number of packets unnecessarily transmitted on a congested path. - - An issue that has not been addressed in the standards process, and - would not be expected to require standardization, would be a proposal - to send a "new" or presumed-lost packet in response to a duplicate or - partial acknowledgement, if allowed by the congestion window. An - example of this would be sending a new packet in response to a single - duplicate acknowledgement, to keep the `ack clock' going in case no - further acknowledgements would have arrived. Such a proposal is an - example of a beneficial change that does not involve interoperability - and does not affect global congestion control, and that therefore - could be implemented by vendors without requiring the intervention of - the IETF standards process. (This issue has in fact been addressed - in [DMKM00], which suggests that "researchers may wish to experiment - with injecting new traffic into the network when duplicate - acknowledgements are being received, as described in [TCPB98] and - [TCPF98]." - -9.5. Other aspects of TCP congestion control. - - Other aspects of TCP congestion control that have not been discussed - in any of the sections above include TCP's recovery from an idle or - application-limited period [HPF00]. - -10. Security Considerations - - This document has been about the risks associated with congestion - control, or with the absence of congestion control. Section 3.2 - discusses the potentials for unfairness if competing flows don't use - compatible congestion control mechanisms, and Section 5 considers the - dangers of congestion collapse if flows don't use end-to-end - congestion control. - - - -Floyd, ed. Best Current Practice [Page 15] - -RFC 2914 Congestion Control Principles September 2000 - - - Because this document does not propose any specific congestion - control mechanisms, it is also not necessary to present specific - security measures associated with congestion control. However, we - would note that there are a range of security considerations - associated with congestion control that should be considered in IETF - documents. - - For example, individual congestion control mechanisms should be as - robust as possible to the attempts of individual end-nodes to subvert - end-to-end congestion control [SCWA99]. This is a particular concern - in multicast congestion control, because of the far-reaching - distribution of the traffic and the greater opportunities for - individual receivers to fail to report congestion. - - RFC 2309 also discussed the potential dangers to the Internet of - unresponsive flows, that is, flows that don't reduce their sending - rate in the presence of congestion, and describes the need for - mechanisms in the network to deal with flows that are unresponsive to - congestion notification. We would note that there is still a need - for research, engineering, measurement, and deployment in these - areas. - - Because the Internet aggregates very large numbers of flows, the risk - to the whole infrastructure of subverting the congestion control of a - few individual flows is limited. Rather, the risk to the - infrastructure would come from the widespread deployment of many - end-nodes subverting end-to-end congestion control. - -AUTHOR'S ADDRESS - - Sally Floyd - AT&T Center for Internet Research at ICSI (ACIRI) - - Phone: +1 (510) 642-4274 x189 - EMail: floyd@aciri.org - URL: http://www.aciri.org/floyd/ - - - - - - - - - - - - - - - -Floyd, ed. Best Current Practice [Page 16] - -RFC 2914 Congestion Control Principles September 2000 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Floyd, ed. Best Current Practice [Page 17] - diff --git a/ext/picotcp/RFC/rfc2923.txt b/ext/picotcp/RFC/rfc2923.txt deleted file mode 100644 index 2ac3f3a..0000000 --- a/ext/picotcp/RFC/rfc2923.txt +++ /dev/null @@ -1,843 +0,0 @@ - - - - - - -Network Working Group K. Lahey -Request for Comments: 2923 dotRocket, Inc. -Category: Informational September 2000 - - - TCP Problems with Path MTU Discovery - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - This memo catalogs several known Transmission Control Protocol (TCP) - implementation problems dealing with Path Maximum Transmission Unit - Discovery (PMTUD), including the long-standing black hole problem, - stretch acknowlegements (ACKs) due to confusion between Maximum - Segment Size (MSS) and segment size, and MSS advertisement based on - PMTU. - -1. Introduction - - This memo catalogs several known TCP implementation problems dealing - with Path MTU Discovery [RFC1191], including the long-standing black - hole problem, stretch ACKs due to confusion between MSS and segment - size, and MSS advertisement based on PMTU. The goal in doing so is - to improve conditions in the existing Internet by enhancing the - quality of current TCP/IP implementations. - - While Path MTU Discovery (PMTUD) can be used with any upper-layer - protocol, it is most commonly used by TCP; this document does not - attempt to treat problems encountered by other upper-layer protocols. - Path MTU Discovery for IPv6 [RFC1981] treats only IPv6-dependent - issues, but not the TCP issues brought up in this document. - - Each problem is defined as follows: - - Name of Problem - The name associated with the problem. In this memo, the name is - given as a subsection heading. - - - - - -Lahey Informational [Page 1] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - Classification - One or more problem categories for which the problem is - classified: "congestion control", "performance", "reliability", - "non-interoperation -- connectivity failure". - - Description - A definition of the problem, succinct but including necessary - background material. - - Significance - A brief summary of the sorts of environments for which the problem - is significant. - - Implications - Why the problem is viewed as a problem. - - Relevant RFCs - The RFCs defining the TCP specification with which the problem - conflicts. These RFCs often qualify behavior using terms such as - MUST, SHOULD, MAY, and others written capitalized. See RFC 2119 - for the exact interpretation of these terms. - - Trace file demonstrating the problem - One or more ASCII trace files demonstrating the problem, if - applicable. - - Trace file demonstrating correct behavior - One or more examples of how correct behavior appears in a trace, - if applicable. - - References - References that further discuss the problem. - - How to detect - How to test an implementation to see if it exhibits the problem. - This discussion may include difficulties and subtleties associated - with causing the problem to manifest itself, and with interpreting - traces to detect the presence of the problem (if applicable). - - How to fix - For known causes of the problem, how to correct the - implementation. - - - - - - - - - -Lahey Informational [Page 2] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - -2. Known implementation problems - -2.1. - - Name of Problem - Black Hole Detection - - Classification - Non-interoperation -- connectivity failure - - Description - A host performs Path MTU Discovery by sending out as large a - packet as possible, with the Don't Fragment (DF) bit set in the IP - header. If the packet is too large for a router to forward on to - a particular link, the router must send an ICMP Destination - Unreachable -- Fragmentation Needed message to the source address. - The host then adjusts the packet size based on the ICMP message. - - As was pointed out in [RFC1435], routers don't always do this - correctly -- many routers fail to send the ICMP messages, for a - variety of reasons ranging from kernel bugs to configuration - problems. Firewalls are often misconfigured to suppress all ICMP - messages. IPsec [RFC2401] and IP-in-IP [RFC2003] tunnels - shouldn't cause these sorts of problems, if the implementations - follow the advice in the appropriate documents. - - PMTUD, as documented in [RFC1191], fails when the appropriate ICMP - messages are not received by the originating host. The upper- - layer protocol continues to try to send large packets and, without - the ICMP messages, never discovers that it needs to reduce the - size of those packets. Its packets are disappearing into a PMTUD - black hole. - - Significance - When PMTUD fails due to the lack of ICMP messages, TCP will also - completely fail under some conditions. - - Implications - This failure is especially difficult to debug, as pings and some - interactive TCP connections to the destination host work. Bulk - transfers fail with the first large packet and the connection - eventually times out. - - These situations can almost always be blamed on a misconfiguration - within the network, which should be corrected. However it seems - inappropriate for some TCP implementations to suffer - - - - - -Lahey Informational [Page 3] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - interoperability failures over paths which do not affect other TCP - implementations (i.e. those without PMTUD). This creates a market - disincentive for deploying TCP implementation with PMTUD enabled. - - Relevant RFCs - RFC 1191 describes Path MTU Discovery. RFC 1435 provides an early - description of these sorts of problems. - - Trace file demonstrating the problem - Made using tcpdump [Jacobson89] recording at an intermediate host. - - 20:12:11.951321 A > B: S 1748427200:1748427200(0) - win 49152 - 20:12:11.951829 B > A: S 1001927984:1001927984(0) - ack 1748427201 win 16384 - 20:12:11.955230 A > B: . ack 1 win 49152 (DF) - 20:12:11.959099 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:12:13.139074 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:12:16.188685 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:12:22.290483 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:12:34.491856 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:12:58.896405 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:13:47.703184 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:14:52.780640 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:15:57.856037 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:17:02.932431 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:18:08.009337 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:19:13.090521 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:20:18.168066 A > B: . 1:1461(1460) ack 1 win 49152 (DF) - 20:21:23.242761 A > B: R 1461:1461(0) ack 1 win 49152 (DF) - - The short SYN packet has no trouble traversing the network, due to - its small size. Similarly, ICMP echo packets used to diagnose - connectivity problems will succeed. - - Large data packets fail to traverse the network. Eventually the - connection times out. This can be especially confusing when the - application starts out with a very small write, which succeeds, - following up with many large writes, which then fail. - - Trace file demonstrating correct behavior - - Made using tcpdump recording at an intermediate host. - - 16:48:42.659115 A > B: S 271394446:271394446(0) - win 8192 (DF) - 16:48:42.672279 B > A: S 2837734676:2837734676(0) - ack 271394447 win 16384 - - - -Lahey Informational [Page 4] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - 16:48:42.676890 A > B: . ack 1 win 8760 (DF) - 16:48:42.870574 A > B: . 1:1461(1460) ack 1 win 8760 (DF) - 16:48:42.871799 A > B: . 1461:2921(1460) ack 1 win 8760 (DF) - 16:48:45.786814 A > B: . 1:1461(1460) ack 1 win 8760 (DF) - 16:48:51.794676 A > B: . 1:1461(1460) ack 1 win 8760 (DF) - 16:49:03.808912 A > B: . 1:537(536) ack 1 win 8760 - 16:49:04.016476 B > A: . ack 537 win 16384 - 16:49:04.021245 A > B: . 537:1073(536) ack 1 win 8760 - 16:49:04.021697 A > B: . 1073:1609(536) ack 1 win 8760 - 16:49:04.120694 B > A: . ack 1609 win 16384 - 16:49:04.126142 A > B: . 1609:2145(536) ack 1 win 8760 - - In this case, the sender sees four packets fail to traverse the - network (using a two-packet initial send window) and turns off - PMTUD. All subsequent packets have the DF flag turned off, and - the size set to the default value of 536 [RFC1122]. - - References - This problem has been discussed extensively on the tcp-impl - mailing list; the name "black hole" has been in use for many - years. - - How to detect - This shows up as a TCP connection which hangs (fails to make - progress) until closed by timeout (this often manifests itself as - a connection that connects and starts to transfer, then eventually - terminates after 15 minutes with zero bytes transfered). This is - particularly annoying with an application like ftp, which will - work perfectly while it uses small packets for control - information, and then fail on bulk transfers. - - A series of ICMP echo packets will show that the two end hosts are - still capable of passing packets, a series of MTU-sized ICMP echo - packets will show some fragmentation, and a series of MTU-sized - ICMP echo packets with DF set will fail. This can be confusing - for network engineers trying to diagnose the problem. - - There are several traceroute implementations that do PMTUD, and - can demonstrate the problem. - - How to fix - TCP should notice that the connection is timing out. After - several timeouts, TCP should attempt to send smaller packets, - perhaps turning off the DF flag for each packet. If this - succeeds, it should continue to turn off PMTUD for the connection - for some reasonable period of time, after which it should probe - again to try to determine if the path has changed. - - - - -Lahey Informational [Page 5] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - Note that, under IPv6, there is no DF bit -- it is implicitly on - at all times. Fragmentation is not allowed in routers, only at - the originating host. Fortunately, the minimum supported MTU for - IPv6 is 1280 octets, which is significantly larger than the 68 - octet minimum in IPv4. This should make it more reasonable for - IPv6 TCP implementations to fall back to 1280 octet packets, when - IPv4 implementations will probably have to turn off DF to respond - to black hole detection. - - Ideally, the ICMP black holes should be fixed when they are found. - - If hosts start to implement black hole detection, it may be that - these problems will go unnoticed and unfixed. This is especially - unfortunate, since detection can take several seconds each time, - and these delays could result in a significant, hidden degradation - of performance. Hosts that implement black hole detection should - probably log detected black holes, so that they can be fixed. - -2.2. - - Name of Problem - Stretch ACK due to PMTUD - - Classification - Congestion Control / Performance - - Description - When a naively implemented TCP stack communicates with a PMTUD - equipped stack, it will try to generate an ACK for every second - full-sized segment. If it determines the full-sized segment based - on the advertised MSS, this can degrade badly in the face of - PMTUD. - - The PMTU can wind up being a small fraction of the advertised MSS; - in this case, an ACK would be generated only very infrequently. - - Significance - - Stretch ACKs have a variety of unfortunate effects, more fully - outlined in [RFC2525]. Most of these have to do with encouraging - a more bursty connection, due to the infrequent arrival of ACKs. - They can also impede congestion window growth. - - Implications - - The complete implications of stretch ACKs are outlined in - [RFC2525]. - - - - -Lahey Informational [Page 6] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - Relevant RFCs - RFC 1122 outlines the requirements for frequency of ACK - generation. [RFC2581] expands on this and clarifies that delayed - ACK is a SHOULD, not a MUST. - - Trace file demonstrating it - - Made using tcpdump recording at an intermediate host. The - timestamp options from all but the first two packets have been - removed for clarity. - - 18:16:52.976657 A > B: S 3183102292:3183102292(0) win 16384 - (DF) - 18:16:52.979580 B > A: S 2022212745:2022212745(0) ack 3183102293 win - 49152 (DF) - 18:16:52.979738 A > B: . ack 1 win 17248 (DF) - 18:16:52.982473 A > B: . 1:4301(4300) ack 1 win 17248 (DF) - 18:16:52.982557 C > A: icmp: B unreachable - - need to frag (mtu 1500)! (DF) - 18:16:52.985839 B > A: . ack 1 win 32768 (DF) - 18:16:54.129928 A > B: . 1:1449(1448) ack 1 win 17248 (DF) - . - . - . - 18:16:58.507078 A > B: . 1463941:1465389(1448) ack 1 win 17248 (DF) - 18:16:58.507200 A > B: . 1465389:1466837(1448) ack 1 win 17248 (DF) - 18:16:58.507326 A > B: . 1466837:1468285(1448) ack 1 win 17248 (DF) - 18:16:58.507439 A > B: . 1468285:1469733(1448) ack 1 win 17248 (DF) - 18:16:58.524763 B > A: . ack 1452357 win 32768 (DF) - 18:16:58.524986 B > A: . ack 1461045 win 32768 (DF) - 18:16:58.525138 A > B: . 1469733:1471181(1448) ack 1 win 17248 (DF) - 18:16:58.525268 A > B: . 1471181:1472629(1448) ack 1 win 17248 (DF) - 18:16:58.525393 A > B: . 1472629:1474077(1448) ack 1 win 17248 (DF) - 18:16:58.525516 A > B: . 1474077:1475525(1448) ack 1 win 17248 (DF) - 18:16:58.525642 A > B: . 1475525:1476973(1448) ack 1 win 17248 (DF) - 18:16:58.525766 A > B: . 1476973:1478421(1448) ack 1 win 17248 (DF) - 18:16:58.526063 A > B: . 1478421:1479869(1448) ack 1 win 17248 (DF) - 18:16:58.526187 A > B: . 1479869:1481317(1448) ack 1 win 17248 (DF) - 18:16:58.526310 A > B: . 1481317:1482765(1448) ack 1 win 17248 (DF) - 18:16:58.526432 A > B: . 1482765:1484213(1448) ack 1 win 17248 (DF) - 18:16:58.526561 A > B: . 1484213:1485661(1448) ack 1 win 17248 (DF) - 18:16:58.526671 A > B: . 1485661:1487109(1448) ack 1 win 17248 (DF) - 18:16:58.537944 B > A: . ack 1478421 win 32768 (DF) - 18:16:58.538328 A > B: . 1487109:1488557(1448) ack 1 win 17248 (DF) - - - - - - - -Lahey Informational [Page 7] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - Note that the interval between ACKs is significantly larger than two - times the segment size; it works out to be almost exactly two times - the advertised MSS. This transfer was long enough that it could be - verified that the stretch ACK was not the result of lost ACK packets. - - Trace file demonstrating correct behavior - - Made using tcpdump recording at an intermediate host. The timestamp - options from all but the first two packets have been removed for - clarity. - - 18:13:32.287965 A > B: S 2972697496:2972697496(0) - win 16384 (DF) - 18:13:32.290785 B > A: S 245639054:245639054(0) - ack 2972697497 win 34496 (DF) - 18:13:32.290941 A > B: . ack 1 win 17248 (DF) - 18:13:32.293774 A > B: . 1:4313(4312) ack 1 win 17248 (DF) - 18:13:32.293856 C > A: icmp: B unreachable - - need to frag (mtu 1500)! (DF) - 18:13:33.637338 A > B: . 1:1461(1460) ack 1 win 17248 (DF) - . - . - . - 18:13:35.561691 A > B: . 1514021:1515481(1460) ack 1 win 17248 (DF) - 18:13:35.561814 A > B: . 1515481:1516941(1460) ack 1 win 17248 (DF) - 18:13:35.561938 A > B: . 1516941:1518401(1460) ack 1 win 17248 (DF) - 18:13:35.562059 A > B: . 1518401:1519861(1460) ack 1 win 17248 (DF) - 18:13:35.562174 A > B: . 1519861:1521321(1460) ack 1 win 17248 (DF) - 18:13:35.564008 B > A: . ack 1481901 win 64680 (DF) - 18:13:35.564383 A > B: . 1521321:1522781(1460) ack 1 win 17248 (DF) - 18:13:35.564499 A > B: . 1522781:1524241(1460) ack 1 win 17248 (DF) - 18:13:35.615576 B > A: . ack 1484821 win 64680 (DF) - 18:13:35.615646 B > A: . ack 1487741 win 64680 (DF) - 18:13:35.615716 B > A: . ack 1490661 win 64680 (DF) - 18:13:35.615784 B > A: . ack 1493581 win 64680 (DF) - 18:13:35.615856 B > A: . ack 1496501 win 64680 (DF) - 18:13:35.615952 A > B: . 1524241:1525701(1460) ack 1 win 17248 (DF) - 18:13:35.615966 B > A: . ack 1499421 win 64680 (DF) - 18:13:35.616088 A > B: . 1525701:1527161(1460) ack 1 win 17248 (DF) - 18:13:35.616105 B > A: . ack 1502341 win 64680 (DF) - 18:13:35.616211 A > B: . 1527161:1528621(1460) ack 1 win 17248 (DF) - 18:13:35.616228 B > A: . ack 1505261 win 64680 (DF) - 18:13:35.616327 A > B: . 1528621:1530081(1460) ack 1 win 17248 (DF) - 18:13:35.616349 B > A: . ack 1508181 win 64680 (DF) - 18:13:35.616448 A > B: . 1530081:1531541(1460) ack 1 win 17248 (DF) - 18:13:35.616565 A > B: . 1531541:1533001(1460) ack 1 win 17248 (DF) - 18:13:35.616891 A > B: . 1533001:1534461(1460) ack 1 win 17248 (DF) - - - - -Lahey Informational [Page 8] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - In this trace, an ACK is generated for every two segments that - arrive. (The segment size is slightly larger in this trace, even - though the source hosts are the same, because of the lack of - timestamp options in this trace.) - - How to detect - This condition can be observed in a packet trace when the advertised - MSS is significantly larger than the actual PMTU of a connection. - - How to fix Several solutions for this problem have been proposed: - - A simple solution is to ACK every other packet, regardless of size. - This has the drawback of generating large numbers of ACKs in the face - of lots of very small packets; this shows up with applications like - the X Window System. - - A slightly more complex solution would monitor the size of incoming - segments and try to determine what segment size the sender is using. - This requires slightly more state in the receiver, but has the - advantage of making receiver silly window syndrome avoidance - computations more accurate [RFC813]. - -2.3. - - Name of Problem - Determining MSS from PMTU - - Classification - Performance - - Description - The MSS advertised at the start of a connection should be based on - the MTU of the interfaces on the system. (For efficiency and other - reasons this may not be the largest MSS possible.) Some systems use - PMTUD determined values to determine the MSS to advertise. - - This results in an advertised MSS that is smaller than the largest - MTU the system can receive. - - Significance - The advertised MSS is an indication to the remote system about the - largest TCP segment that can be received [RFC879]. If this value is - too small, the remote system will be forced to use a smaller segment - size when sending, purely because the local system found a particular - PMTU earlier. - - - - - - -Lahey Informational [Page 9] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - Given the asymmetric nature of many routes on the Internet - [Paxson97], it seems entirely possible that the return PMTU is - different from the sending PMTU. Limiting the segment size in this - way can reduce performance and frustrate the PMTUD algorithm. - - Even if the route was symmetric, setting this artificially lowered - limit on segment size will make it impossible to probe later to - determine if the PMTU has changed. - - Implications - The whole point of PMTUD is to send as large a segment as possible. - If long-running connections cannot successfully probe for larger - PMTU, then potential performance gains will be impossible to realize. - This destroys the whole point of PMTUD. - - Relevant RFCs RFC 1191. [RFC879] provides a complete discussion of - MSS calculations and appropriate values. Note that this practice - does not violate any of the specifications in these RFCs. - - Trace file demonstrating it - This trace was made using tcpdump running on an intermediate host. - Host A initiates two separate consecutive connections, A1 and A2, to - host B. Router C is the location of the MTU bottleneck. As usual, - TCP options are removed from all non-SYN packets. - - 22:33:32.305912 A1 > B: S 1523306220:1523306220(0) - win 8760 (DF) - 22:33:32.306518 B > A1: S 729966260:729966260(0) - ack 1523306221 win 16384 - 22:33:32.310307 A1 > B: . ack 1 win 8760 (DF) - 22:33:32.323496 A1 > B: P 1:1461(1460) ack 1 win 8760 (DF) - 22:33:32.323569 C > A1: icmp: 129.99.238.5 unreachable - - need to frag (mtu 1024) (DF) (ttl 255, id 20666) - 22:33:32.783694 A1 > B: . 1:985(984) ack 1 win 8856 (DF) - 22:33:32.840817 B > A1: . ack 985 win 16384 - 22:33:32.845651 A1 > B: . 1461:2445(984) ack 1 win 8856 (DF) - 22:33:32.846094 B > A1: . ack 985 win 16384 - 22:33:33.724392 A1 > B: . 985:1969(984) ack 1 win 8856 (DF) - 22:33:33.724893 B > A1: . ack 2445 win 14924 - 22:33:33.728591 A1 > B: . 2445:2921(476) ack 1 win 8856 (DF) - 22:33:33.729161 A1 > B: . ack 1 win 8856 (DF) - 22:33:33.840758 B > A1: . ack 2921 win 16384 - - [...] - - 22:33:34.238659 A1 > B: F 7301:8193(892) ack 1 win 8856 (DF) - 22:33:34.239036 B > A1: . ack 8194 win 15492 - 22:33:34.239303 B > A1: F 1:1(0) ack 8194 win 16384 - - - -Lahey Informational [Page 10] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - 22:33:34.242971 A1 > B: . ack 2 win 8856 (DF) - 22:33:34.454218 A2 > B: S 1523591299:1523591299(0) - win 8856 (DF) - 22:33:34.454617 B > A2: S 732408874:732408874(0) - ack 1523591300 win 16384 - 22:33:34.457516 A2 > B: . ack 1 win 8856 (DF) - 22:33:34.470683 A2 > B: P 1:985(984) ack 1 win 8856 (DF) - 22:33:34.471144 B > A2: . ack 985 win 16384 - 22:33:34.476554 A2 > B: . 985:1969(984) ack 1 win 8856 (DF) - 22:33:34.477580 A2 > B: P 1969:2953(984) ack 1 win 8856 (DF) - - [...] - - Notice that the SYN packet for session A2 specifies an MSS of 984. - - Trace file demonstrating correct behavior - - As before, this trace was made using tcpdump running on an - intermediate host. Host A initiates two separate consecutive - connections, A1 and A2, to host B. Router C is the location of the - MTU bottleneck. As usual, TCP options are removed from all non-SYN - packets. - - 22:36:58.828602 A1 > B: S 3402991286:3402991286(0) win 32768 - (DF) - 22:36:58.844040 B > A1: S 946999880:946999880(0) - ack 3402991287 win 16384 - - 22:36:58.848058 A1 > B: . ack 1 win 32768 (DF) - 22:36:58.851514 A1 > B: P 1:1025(1024) ack 1 win 32768 (DF) - 22:36:58.851584 C > A1: icmp: 129.99.238.5 unreachable - - need to frag (mtu 1024) (DF) - 22:36:58.855885 A1 > B: . 1:969(968) ack 1 win 32768 (DF) - 22:36:58.856378 A1 > B: . 969:985(16) ack 1 win 32768 (DF) - 22:36:59.036309 B > A1: . ack 985 win 16384 - 22:36:59.039255 A1 > B: FP 985:1025(40) ack 1 win 32768 (DF) - 22:36:59.039623 B > A1: . ack 1026 win 16344 - 22:36:59.039828 B > A1: F 1:1(0) ack 1026 win 16384 - 22:36:59.043037 A1 > B: . ack 2 win 32768 (DF) - 22:37:01.436032 A2 > B: S 3404812097:3404812097(0) win 32768 - (DF) - 22:37:01.436424 B > A2: S 949814769:949814769(0) - ack 3404812098 win 16384 - - 22:37:01.440147 A2 > B: . ack 1 win 32768 (DF) - 22:37:01.442736 A2 > B: . 1:969(968) ack 1 win 32768 (DF) - - - -Lahey Informational [Page 11] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - - 22:37:01.442894 A2 > B: P 969:985(16) ack 1 win 32768 (DF) - 22:37:01.443283 B > A2: . ack 985 win 16384 - 22:37:01.446068 A2 > B: P 985:1025(40) ack 1 win 32768 (DF) - 22:37:01.446519 B > A2: . ack 1025 win 16384 - 22:37:01.448465 A2 > B: F 1025:1025(0) ack 1 win 32768 (DF) - 22:37:01.448837 B > A2: . ack 1026 win 16384 - 22:37:01.449007 B > A2: F 1:1(0) ack 1026 win 16384 - 22:37:01.452201 A2 > B: . ack 2 win 32768 (DF) - - Note that the same MSS was used for both session A1 and session A2. - - How to detect - This can be detected using a packet trace of two separate - connections; the first should invoke PMTUD; the second should start - soon enough after the first that the PMTU value does not time out. - - How to fix - The MSS should be determined based on the MTUs of the interfaces on - the system, as outlined in [RFC1122] and [RFC1191]. - -3. Security Considerations - - The one security concern raised by this memo is that ICMP black holes - are often caused by over-zealous security administrators who block - all ICMP messages. It is vitally important that those who design and - deploy security systems understand the impact of strict filtering on - upper-layer protocols. The safest web site in the world is worthless - if most TCP implementations cannot transfer data from it. It would - be far nicer to have all of the black holes fixed rather than fixing - all of the TCP implementations. - -4. Acknowledgements - - Thanks to Mark Allman, Vern Paxson, and Jamshid Mahdavi for generous - help reviewing the document, and to Matt Mathis for early suggestions - of various mechanisms that can cause PMTUD black holes, as well as - review. The structure for describing TCP problems, and the early - description of that structure is from [RFC2525]. Special thanks to - Amy Bock, who helped perform the PMTUD tests which discovered these - bugs. - - - - - - - - - - - -Lahey Informational [Page 12] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - -5. References - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC1122] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC813] Clark, D., "Window and Acknowledgement Strategy in TCP", - RFC 813, July 1982. - - [Jacobson89] V. Jacobson, C. Leres, and S. McCanne, tcpdump, June - 1989, ftp.ee.lbl.gov - - [RFC1435] Knowles, S., "IESG Advice from Experience with Path MTU - Discovery", RFC 1435, March 1993. - - [RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC - 1191, November 1990. - - [RFC1981] McCann, J., Deering, S. and J. Mogul, "Path MTU - Discovery for IP version 6", RFC 1981, August 1996. - - [Paxson96] V. Paxson, "End-to-End Routing Behavior in the - Internet", IEEE/ACM Transactions on Networking (5), - pp.~601-615, Oct. 1997. - - [RFC2525] Paxon, V., Allman, M., Dawson, S., Fenner, W., Griner, - J., Heavens, I., Lahey, K., Semke, I. and B. Volz, - "Known TCP Implementation Problems", RFC 2525, March - 1999. - - [RFC879] Postel, J., "The TCP Maximum Segment Size and Related - Topics", RFC 879, November 1983. - - [RFC2001] Stevens, W., "TCP Slow Start, Congestion Avoidance, Fast - Retransmit, and Fast Recovery Algorithms", RFC 2001, - January 1997. - - - - - - - - - - - - - -Lahey Informational [Page 13] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - -6. Author's Address - - Kevin Lahey - dotRocket, Inc. - 1901 S. Bascom Ave., Suite 300 - Campbell, CA 95008 - USA - - Phone: +1 408-371-8977 x115 - email: kml@dotrocket.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Lahey Informational [Page 14] - -RFC 2923 TCP Problems with Path MTU Discovery September 2000 - - -7. Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Lahey Informational [Page 15] - diff --git a/ext/picotcp/RFC/rfc2988.txt b/ext/picotcp/RFC/rfc2988.txt deleted file mode 100644 index 2815ac8..0000000 --- a/ext/picotcp/RFC/rfc2988.txt +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - -Network Working Group V. Paxson -Request for Comments: 2988 ACIRI -Category: Standards Track M. Allman - NASA GRC/BBN - November 2000 - - - Computing TCP's Retransmission Timer - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -Abstract - - This document defines the standard algorithm that Transmission - Control Protocol (TCP) senders are required to use to compute and - manage their retransmission timer. It expands on the discussion in - section 4.2.3.1 of RFC 1122 and upgrades the requirement of - supporting the algorithm from a SHOULD to a MUST. - -1 Introduction - - The Transmission Control Protocol (TCP) [Pos81] uses a retransmission - timer to ensure data delivery in the absence of any feedback from the - remote data receiver. The duration of this timer is referred to as - RTO (retransmission timeout). RFC 1122 [Bra89] specifies that the - RTO should be calculated as outlined in [Jac88]. - - This document codifies the algorithm for setting the RTO. In - addition, this document expands on the discussion in section 4.2.3.1 - of RFC 1122 and upgrades the requirement of supporting the algorithm - from a SHOULD to a MUST. RFC 2581 [APS99] outlines the algorithm TCP - uses to begin sending after the RTO expires and a retransmission is - sent. This document does not alter the behavior outlined in RFC 2581 - [APS99]. - - - - - - - -Paxson & Allman Standards Track [Page 1] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - - In some situations it may be beneficial for a TCP sender to be more - conservative than the algorithms detailed in this document allow. - However, a TCP MUST NOT be more aggressive than the following - algorithms allow. - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in [Bra97]. - -2 The Basic Algorithm - - To compute the current RTO, a TCP sender maintains two state - variables, SRTT (smoothed round-trip time) and RTTVAR (round-trip - time variation). In addition, we assume a clock granularity of G - seconds. - - The rules governing the computation of SRTT, RTTVAR, and RTO are as - follows: - - (2.1) Until a round-trip time (RTT) measurement has been made for a - segment sent between the sender and receiver, the sender SHOULD - set RTO <- 3 seconds (per RFC 1122 [Bra89]), though the - "backing off" on repeated retransmission discussed in (5.5) - still applies. - - Note that some implementations may use a "heartbeat" timer - that in fact yield a value between 2.5 seconds and 3 - seconds. Accordingly, a lower bound of 2.5 seconds is also - acceptable, providing that the timer will never expire - faster than 2.5 seconds. Implementations using a heartbeat - timer with a granularity of G SHOULD not set the timer below - 2.5 + G seconds. - - (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) - - where K = 4. - - (2.3) When a subsequent RTT measurement R' is made, a host MUST set - - RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'| - SRTT <- (1 - alpha) * SRTT + alpha * R' - - - - - - -Paxson & Allman Standards Track [Page 2] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - - The value of SRTT used in the update to RTTVAR is its value - before updating SRTT itself using the second assignment. That - is, updating RTTVAR and SRTT MUST be computed in the above - order. - - The above SHOULD be computed using alpha=1/8 and beta=1/4 (as - suggested in [JK88]). - - After the computation, a host MUST update - RTO <- SRTT + max (G, K*RTTVAR) - - (2.4) Whenever RTO is computed, if it is less than 1 second then the - RTO SHOULD be rounded up to 1 second. - - Traditionally, TCP implementations use coarse grain clocks to - measure the RTT and trigger the RTO, which imposes a large - minimum value on the RTO. Research suggests that a large - minimum RTO is needed to keep TCP conservative and avoid - spurious retransmissions [AP99]. Therefore, this - specification requires a large minimum RTO as a conservative - approach, while at the same time acknowledging that at some - future point, research may show that a smaller minimum RTO is - acceptable or superior. - - (2.5) A maximum value MAY be placed on RTO provided it is at least 60 - seconds. - -3 Taking RTT Samples - - TCP MUST use Karn's algorithm [KP87] for taking RTT samples. That - is, RTT samples MUST NOT be made using segments that were - retransmitted (and thus for which it is ambiguous whether the reply - was for the first instance of the packet or a later instance). The - only case when TCP can safely take RTT samples from retransmitted - segments is when the TCP timestamp option [JBB92] is employed, since - the timestamp option removes the ambiguity regarding which instance - of the data segment triggered the acknowledgment. - - Traditionally, TCP implementations have taken one RTT measurement at - a time (typically once per RTT). However, when using the timestamp - option, each ACK can be used as an RTT sample. RFC 1323 [JBB92] - suggests that TCP connections utilizing large congestion windows - should take many RTT samples per window of data to avoid aliasing - effects in the estimated RTT. A TCP implementation MUST take at - least one RTT measurement per RTT (unless that is not possible per - Karn's algorithm). - - - - - -Paxson & Allman Standards Track [Page 3] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - - For fairly modest congestion window sizes research suggests that - timing each segment does not lead to a better RTT estimator [AP99]. - Additionally, when multiple samples are taken per RTT the alpha and - beta defined in section 2 may keep an inadequate RTT history. A - method for changing these constants is currently an open research - question. - -4 Clock Granularity - - There is no requirement for the clock granularity G used for - computing RTT measurements and the different state variables. - However, if the K*RTTVAR term in the RTO calculation equals zero, - the variance term MUST be rounded to G seconds (i.e., use the - equation given in step 2.3). - - RTO <- SRTT + max (G, K*RTTVAR) - - Experience has shown that finer clock granularities (<= 100 msec) - perform somewhat better than more coarse granularities. - - Note that [Jac88] outlines several clever tricks that can be used to - obtain better precision from coarse granularity timers. These - changes are widely implemented in current TCP implementations. - -5 Managing the RTO Timer - - An implementation MUST manage the retransmission timer(s) in such a - way that a segment is never retransmitted too early, i.e. less than - one RTO after the previous transmission of that segment. - - The following is the RECOMMENDED algorithm for managing the - retransmission timer: - - (5.1) Every time a packet containing data is sent (including a - retransmission), if the timer is not running, start it running - so that it will expire after RTO seconds (for the current value - of RTO). - - (5.2) When all outstanding data has been acknowledged, turn off the - retransmission timer. - - (5.3) When an ACK is received that acknowledges new data, restart the - retransmission timer so that it will expire after RTO seconds - (for the current value of RTO). - - - - - - - -Paxson & Allman Standards Track [Page 4] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - - When the retransmission timer expires, do the following: - - (5.4) Retransmit the earliest segment that has not been acknowledged - by the TCP receiver. - - (5.5) The host MUST set RTO <- RTO * 2 ("back off the timer"). The - maximum value discussed in (2.5) above may be used to provide an - upper bound to this doubling operation. - - (5.6) Start the retransmission timer, such that it expires after RTO - seconds (for the value of RTO after the doubling operation - outlined in 5.5). - - Note that after retransmitting, once a new RTT measurement is - obtained (which can only happen when new data has been sent and - acknowledged), the computations outlined in section 2 are performed, - including the computation of RTO, which may result in "collapsing" - RTO back down after it has been subject to exponential backoff - (rule 5.5). - - Note that a TCP implementation MAY clear SRTT and RTTVAR after - backing off the timer multiple times as it is likely that the - current SRTT and RTTVAR are bogus in this situation. Once SRTT and - RTTVAR are cleared they should be initialized with the next RTT - sample taken per (2.2) rather than using (2.3). - -6 Security Considerations - - This document requires a TCP to wait for a given interval before - retransmitting an unacknowledged segment. An attacker could cause a - TCP sender to compute a large value of RTO by adding delay to a - timed packet's latency, or that of its acknowledgment. However, - the ability to add delay to a packet's latency often coincides with - the ability to cause the packet to be lost, so it is difficult to - see what an attacker might gain from such an attack that could cause - more damage than simply discarding some of the TCP connection's - packets. - - The Internet to a considerable degree relies on the correct - implementation of the RTO algorithm (as well as those described in - RFC 2581) in order to preserve network stability and avoid - congestion collapse. An attacker could cause TCP endpoints to - respond more aggressively in the face of congestion by forging - acknowledgments for segments before the receiver has actually - received the data, thus lowering RTO to an unsafe value. But to do - so requires spoofing the acknowledgments correctly, which is - difficult unless the attacker can monitor traffic along the path - between the sender and the receiver. In addition, even if the - - - -Paxson & Allman Standards Track [Page 5] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - - attacker can cause the sender's RTO to reach too small a value, it - appears the attacker cannot leverage this into much of an attack - (compared to the other damage they can do if they can spoof packets - belonging to the connection), since the sending TCP will still back - off its timer in the face of an incorrectly transmitted packet's - loss due to actual congestion. - -Acknowledgments - - The RTO algorithm described in this memo was originated by Van - Jacobson in [Jac88]. - -References - - [AP99] Allman, M. and V. Paxson, "On Estimating End-to-End Network - Path Properties", SIGCOMM 99. - - [APS99] Allman, M., Paxson V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [Bra89] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [Bra97] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [Jac88] Jacobson, V., "Congestion Avoidance and Control", Computer - Communication Review, vol. 18, no. 4, pp. 314-329, Aug. 1988. - - [JK88] Jacobson, V. and M. Karels, "Congestion Avoidance and - Control", ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z. - - [KP87] Karn, P. and C. Partridge, "Improving Round-Trip Time - Estimates in Reliable Transport Protocols", SIGCOMM 87. - - [Pos81] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, - September 1981. - - - - - - - - - - - - - - -Paxson & Allman Standards Track [Page 6] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - -Author's Addresses - - Vern Paxson - ACIRI / ICSI - 1947 Center Street - Suite 600 - Berkeley, CA 94704-1198 - - Phone: 510-666-2882 - Fax: 510-643-7684 - EMail: vern@aciri.org - http://www.aciri.org/vern/ - - - Mark Allman - NASA Glenn Research Center/BBN Technologies - Lewis Field - 21000 Brookpark Rd. MS 54-2 - Cleveland, OH 44135 - - Phone: 216-433-6586 - Fax: 216-433-8705 - EMail: mallman@grc.nasa.gov - http://roland.grc.nasa.gov/~mallman - - - - - - - - - - - - - - - - - - - - - - - - - - - -Paxson & Allman Standards Track [Page 7] - -RFC 2988 Computing TCP's Retransmission Timer November 2000 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Paxson & Allman Standards Track [Page 8] - diff --git a/ext/picotcp/RFC/rfc3042.txt b/ext/picotcp/RFC/rfc3042.txt deleted file mode 100644 index a190655..0000000 --- a/ext/picotcp/RFC/rfc3042.txt +++ /dev/null @@ -1,507 +0,0 @@ - - - - - - -Network Working Group M. Allman -Request for Comments: 3042 NASA GRC/BBN -Category: Standards Track H. Balakrishnan - MIT - S. Floyd - ACIRI - January 2001 - - - Enhancing TCP's Loss Recovery Using Limited Transmit - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2001). All Rights Reserved. - -Abstract - - This document proposes a new Transmission Control Protocol (TCP) - mechanism that can be used to more effectively recover lost segments - when a connection's congestion window is small, or when a large - number of segments are lost in a single transmission window. The - "Limited Transmit" algorithm calls for sending a new data segment in - response to each of the first two duplicate acknowledgments that - arrive at the sender. Transmitting these segments increases the - probability that TCP can recover from a single lost segment using the - fast retransmit algorithm, rather than using a costly retransmission - timeout. Limited Transmit can be used both in conjunction with, and - in the absence of, the TCP selective acknowledgment (SACK) mechanism. - -1 Introduction - - A number of researchers have observed that TCP's loss recovery - strategies do not work well when the congestion window at a TCP - sender is small. This can happen, for instance, because there is - only a limited amount of data to send, or because of the limit - imposed by the receiver-advertised window, or because of the - constraints imposed by end-to-end congestion control over a - connection with a small bandwidth-delay product - [Riz96,Mor97,BPS+98,Bal98,LK98]. When a TCP detects a missing - segment, it enters a loss recovery phase using one of two methods. - - - -Allman, et al. Standards Track [Page 1] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - - First, if an acknowledgment (ACK) for a given segment is not received - in a certain amount of time a retransmission timeout occurs and the - segment is resent [RFC793,PA00]. Second, the "Fast Retransmit" - algorithm resends a segment when three duplicate ACKs arrive at the - sender [Jac88,RFC2581]. However, because duplicate ACKs from the - receiver are also triggered by packet reordering in the Internet, the - TCP sender waits for three duplicate ACKs in an attempt to - disambiguate segment loss from packet reordering. Once in a loss - recovery phase, a number of techniques can be used to retransmit lost - segments, including slow start-based recovery or Fast Recovery - [RFC2581], NewReno [RFC2582], and loss recovery based on selective - acknowledgments (SACKs) [RFC2018,FF96]. - - TCP's retransmission timeout (RTO) is based on measured round-trip - times (RTT) between the sender and receiver, as specified in [PA00]. - To prevent spurious retransmissions of segments that are only delayed - and not lost, the minimum RTO is conservatively chosen to be 1 - second. Therefore, it behooves TCP senders to detect and recover - from as many losses as possible without incurring a lengthy timeout - when the connection remains idle. However, if not enough duplicate - ACKs arrive from the receiver, the Fast Retransmit algorithm is never - triggered---this situation occurs when the congestion window is small - or if a large number of segments in a window are lost. For instance, - consider a congestion window (cwnd) of three segments. If one - segment is dropped by the network, then at most two duplicate ACKs - will arrive at the sender. Since three duplicate ACKs are required - to trigger Fast Retransmit, a timeout will be required to resend the - dropped packet. - - [BPS+97] found that roughly 56% of retransmissions sent by a busy web - server were sent after the RTO expires, while only 44% were handled - by Fast Retransmit. In addition, only 4% of the RTO-based - retransmissions could have been avoided with SACK, which of course - has to continue to disambiguate reordering from genuine loss. In - contrast, using the technique outlined in this document and in - [Bal98], 25% of the RTO-based retransmissions in that dataset would - have likely been avoided. - - The next section of this document outlines small changes to TCP - senders that will decrease the reliance on the retransmission timer, - and thereby improve TCP performance when Fast Retransmit is not - triggered. These changes do not adversely affect the performance of - TCP nor interact adversely with other connections, in other - circumstances. - - - - - - - -Allman, et al. Standards Track [Page 2] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - -1.1 Terminology - - In this document, he key words "MUST", "MUST NOT", "REQUIRED", - "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", - AND "OPTIONAL" are to be interpreted as described in RFC 2119 [1] and - indicate requirement levels for protocols. - -2 The Limited Transmit Algorithm - - When a TCP sender has previously unsent data queued for transmission - it SHOULD use the Limited Transmit algorithm, which calls for a TCP - sender to transmit new data upon the arrival of the first two - consecutive duplicate ACKs when the following conditions are - satisfied: - - * The receiver's advertised window allows the transmission of the - segment. - - * The amount of outstanding data would remain less than or equal - to the congestion window plus 2 segments. In other words, the - sender can only send two segments beyond the congestion window - (cwnd). - - The congestion window (cwnd) MUST NOT be changed when these new - segments are transmitted. Assuming that these new segments and the - corresponding ACKs are not dropped, this procedure allows the sender - to infer loss using the standard Fast Retransmit threshold of three - duplicate ACKs [RFC2581]. This is more robust to reordered packets - than if an old packet were retransmitted on the first or second - duplicate ACK. - - Note: If the connection is using selective acknowledgments [RFC2018], - the data sender MUST NOT send new segments in response to duplicate - ACKs that contain no new SACK information, as a misbehaving receiver - can generate such ACKs to trigger inappropriate transmission of data - segments. See [SCWA99] for a discussion of attacks by misbehaving - receivers. - - Limited Transmit follows the "conservation of packets" congestion - control principle [Jac88]. Each of the first two duplicate ACKs - indicate that a segment has left the network. Furthermore, the - sender has not yet decided that a segment has been dropped and - therefore has no reason to assume that the current congestion control - state is inaccurate. Therefore, transmitting segments does not - deviate from the spirit of TCP's congestion control principles. - - - - - - -Allman, et al. Standards Track [Page 3] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - - [BPS99] shows that packet reordering is not a rare network event. - [RFC2581] does not provide for sending of data on the first two - duplicate ACKs that arrive at the sender. This causes a burst of - segments to be sent when an ACK for new data does arrive following - packet reordering. Using Limited Transmit, data packets will be - clocked out by incoming ACKs and therefore transmission will not be - as bursty. - - Note: Limited Transmit is implemented in the ns simulator [NS]. - Researchers wishing to investigate this mechanism further can do so - by enabling "singledup_" for the given TCP connection. - -3 Related Work - - Deployment of Explicit Congestion Notification (ECN) [Flo94,RFC2481] - may benefit connections with small congestion window sizes [SA00]. - ECN provides a method for indicating congestion to the end-host - without dropping segments. While some segment drops may still occur, - ECN may allow TCP to perform better with small congestion window - sizes because the sender can avoid many of the Fast Retransmits and - Retransmit Timeouts that would otherwise have been needed to detect - dropped segments [SA00]. - - When ECN-enabled TCP traffic competes with non-ECN-enabled TCP - traffic, ECN-enabled traffic can receive up to 30% higher goodput. - For bulk transfers, the relative performance benefit of ECN is - greatest when on average each flow has 3-4 outstanding packets during - each round-trip time [ZQ00]. This should be a good estimate for the - performance impact of a flow using Limited Transmit, since both ECN - and Limited Transmit reduce the reliance on the retransmission timer - for signaling congestion. - - The Rate-Halving congestion control algorithm [MSML99] uses a form of - limited transmit, as it calls for transmitting a data segment on - every second duplicate ACK that arrives at the sender. The algorithm - decouples the decision of what to send from the decision of when to - send. However, similar to Limited Transmit the algorithm will always - send a new data segment on the second duplicate ACK that arrives at - the sender. - -4 Security Considerations - - The additional security implications of the changes proposed in this - document, compared to TCP's current vulnerabilities, are minimal. - The potential security issues come from the subversion of end-to-end - congestion control from "false" duplicate ACKs, where a "false" - duplicate ACK is a duplicate ACK that does not actually acknowledge - new data received at the TCP receiver. False duplicate ACKs could - - - -Allman, et al. Standards Track [Page 4] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - - result from duplicate ACKs that are themselves duplicated in the - network, or from misbehaving TCP receivers that send false duplicate - ACKs to subvert end-to-end congestion control [SCWA99,RFC2581]. - - When the TCP data receiver has agreed to use the SACK option, the TCP - data sender has fairly strong protection against false duplicate - ACKs. In particular, with SACK, a duplicate ACK that acknowledges - new data arriving at the receiver reports the sequence numbers of - that new data. Thus, with SACK, the TCP sender can verify that an - arriving duplicate ACK acknowledges data that the TCP sender has - actually sent, and for which no previous acknowledgment has been - received, before sending new data as a result of that acknowledgment. - For further protection, the TCP sender could keep a record of packet - boundaries for transmitted data packets, and recognize at most one - valid acknowledgment for each packet (e.g., the first acknowledgment - acknowledging the receipt of all of the sequence numbers in that - packet). - - One could imagine some limited protection against false duplicate - ACKs for a non-SACK TCP connection, where the TCP sender keeps a - record of the number of packets transmitted, and recognizes at most - one acknowledgment per packet to be used for triggering the sending - of new data. However, this accounting of packets transmitted and - acknowledged would require additional state and extra complexity at - the TCP sender, and does not seem necessary. - - The most important protection against false duplicate ACKs comes from - the limited potential of duplicate ACKs in subverting end-to-end - congestion control. There are two separate cases to consider: when - the TCP sender receives less than a threshold number of duplicate - ACKs, and when the TCP sender receives at least a threshold number of - duplicate ACKs. In the latter case a TCP with Limited Transmit will - behave essentially the same as a TCP without Limited Transmit in that - the congestion window will be halved and a loss recovery period will - be initiated. - - When a TCP sender receives less than a threshold number of duplicate - ACKs a misbehaving receiver could send two duplicate ACKs after each - regular ACK. One might imagine that the TCP sender would send at - three times its allowed sending rate. However, using Limited - Transmit as outlined in section 2 the sender is only allowed to - exceed the congestion window by less than the duplicate ACK threshold - (of three segments), and thus would not send a new packet for each - duplicate ACK received. - - - - - - - -Allman, et al. Standards Track [Page 5] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - -Acknowledgments - - Bill Fenner, Jamshid Mahdavi and the Transport Area Working Group - provided valuable feedback on an early version of this document. - -References - - [Bal98] Hari Balakrishnan. Challenges to Reliable Data Transport - over Heterogeneous Wireless Networks. Ph.D. Thesis, - University of California at Berkeley, August 1998. - - [BPS+97] Hari Balakrishnan, Venkata Padmanabhan, Srinivasan Seshan, - Mark Stemm, and Randy Katz. TCP Behavior of a Busy Web - Server: Analysis and Improvements. Technical Report - UCB/CSD-97-966, August 1997. Available from - http://nms.lcs.mit.edu/~hari/papers/csd-97-966.ps. (Also - in Proc. IEEE INFOCOM Conf., San Francisco, CA, March - 1998.) - - [BPS99] Jon Bennett, Craig Partridge, Nicholas Shectman. Packet - Reordering is Not Pathological Network Behavior. IEEE/ACM - Transactions on Networking, December 1999. - - [FF96] Kevin Fall, Sally Floyd. Simulation-based Comparisons of - Tahoe, Reno, and SACK TCP. ACM Computer Communication - Review, July 1996. - - [Flo94] Sally Floyd. TCP and Explicit Congestion Notification. - ACM Computer Communication Review, October 1994. - - [Jac88] Van Jacobson. Congestion Avoidance and Control. ACM - SIGCOMM 1988. - - [LK98] Dong Lin, H.T. Kung. TCP Fast Recovery Strategies: - Analysis and Improvements. Proceedings of InfoCom, March - 1998. - - [MSML99] Matt Mathis, Jeff Semke, Jamshid Mahdavi, Kevin Lahey. The - Rate Halving Algorithm, 1999. URL: - http://www.psc.edu/networking/rate_halving.html. - - [Mor97] Robert Morris. TCP Behavior with Many Flows. Proceedings - of the Fifth IEEE International Conference on Network - Protocols. October 1997. - - [NS] Ns network simulator. URL: http://www.isi.edu/nsnam/. - - - - - -Allman, et al. Standards Track [Page 6] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - - [PA00] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [Riz96] Luigi Rizzo. Issues in the Implementation of Selective - Acknowledgments for TCP. January, 1996. URL: - http://www.iet.unipi.it/~luigi/selack.ps - - [SA00] Hadi Salim, J. and U. Ahmed, "Performance Evaluation of - Explicit Congestion Notification (ECN) in IP Networks", RFC - 2884, July 2000. - - [SCWA99] Stefan Savage, Neal Cardwell, David Wetherall, Tom - Anderson. TCP Congestion Control with a Misbehaving - Receiver. ACM Computer Communications Review, October - 1999. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, October 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2481] Ramakrishnan, K. and S. Floyd, "A Proposal to Add Explicit - Congestion Notification (ECN) to IP", RFC 2481, January - 1999. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2582] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [ZQ00] Yin Zhang and Lili Qiu, Understanding the End-to-End - Performance Impact of RED in a Heterogeneous Environment, - Cornell CS Technical Report 2000-1802, July 2000. URL - http://www.cs.cornell.edu/yzhang/papers.htm. - - - - - - - - - - - - -Allman, et al. Standards Track [Page 7] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - -Authors' Addresses - - Mark Allman - NASA Glenn Research Center/BBN Technologies - Lewis Field - 21000 Brookpark Rd. MS 54-5 - Cleveland, OH 44135 - - Phone: +1-216-433-6586 - Fax: +1-216-433-8705 - EMail: mallman@grc.nasa.gov - http://roland.grc.nasa.gov/~mallman - - - Hari Balakrishnan - Laboratory for Computer Science - 545 Technology Square - Massachusetts Institute of Technology - Cambridge, MA 02139 - - EMail: hari@lcs.mit.edu - http://nms.lcs.mit.edu/~hari/ - - - Sally Floyd - AT&T Center for Internet Research at ICSI (ACIRI) - 1947 Center St, Suite 600 - Berkeley, CA 94704 - - Phone: +1-510-666-2989 - EMail: floyd@aciri.org - http://www.aciri.org/floyd/ - - - - - - - - - - - - - - - - - - - -Allman, et al. Standards Track [Page 8] - -RFC 3042 Enhancing TCP Loss Recovery January 2001 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Allman, et al. Standards Track [Page 9] - diff --git a/ext/picotcp/RFC/rfc3124.txt b/ext/picotcp/RFC/rfc3124.txt deleted file mode 100644 index db57bc3..0000000 --- a/ext/picotcp/RFC/rfc3124.txt +++ /dev/null @@ -1,1235 +0,0 @@ - - - - - - -Network Working Group H. Balakrishnan -Request for Comments: 3124 MIT LCS -Category: Standards Track S. Seshan - CMU - June 2001 - - - The Congestion Manager - - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2001). All Rights Reserved. - -Abstract - - This document describes the Congestion Manager (CM), an end-system - module that: - - (i) Enables an ensemble of multiple concurrent streams from a sender - destined to the same receiver and sharing the same congestion - properties to perform proper congestion avoidance and control, and - - (ii) Allows applications to easily adapt to network congestion. - -1. Conventions used in this document: - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in RFC-2119 [Bradner97]. - - STREAM - - A group of packets that all share the same source and destination - IP address, IP type-of-service, transport protocol, and source and - destination transport-layer port numbers. - - - - - - - -Balakrishnan, et. al. Standards Track [Page 1] - -RFC 3124 The Congestion Manager June 2001 - - - MACROFLOW - - A group of CM-enabled streams that all use the same congestion - management and scheduling algorithms, and share congestion state - information. Currently, streams destined to different receivers - belong to different macroflows. Streams destined to the same - receiver MAY belong to different macroflows. When the Congestion - Manager is in use, streams that experience identical congestion - behavior and use the same congestion control algorithm SHOULD - belong to the same macroflow. - - APPLICATION - - Any software module that uses the CM. This includes user-level - applications such as Web servers or audio/video servers, as well - as in-kernel protocols such as TCP [Postel81] that use the CM for - congestion control. - - WELL-BEHAVED APPLICATION - - An application that only transmits when allowed by the CM and - accurately accounts for all data that it has sent to the receiver - by informing the CM using the CM API. - - PATH MAXIMUM TRANSMISSION UNIT (PMTU) - - The size of the largest packet that the sender can transmit - without it being fragmented en route to the receiver. It includes - the sizes of all headers and data except the IP header. - - CONGESTION WINDOW (cwnd) - - A CM state variable that modulates the amount of outstanding data - between sender and receiver. - - OUTSTANDING WINDOW (ownd) - - The number of bytes that has been transmitted by the source, but - not known to have been either received by the destination or lost - in the network. - - INITIAL WINDOW (IW) - - The size of the sender's congestion window at the beginning of a - macroflow. - - - - - - -Balakrishnan, et. al. Standards Track [Page 2] - -RFC 3124 The Congestion Manager June 2001 - - - DATA TYPE SYNTAX - - We use "u64" for unsigned 64-bit, "u32" for unsigned 32-bit, "u16" - for unsigned 16-bit, "u8" for unsigned 8-bit, "i32" for signed - 32-bit, "i16" for signed 16-bit quantities, "float" for IEEE - floating point values. The type "void" is used to indicate that - no return value is expected from a call. Pointers are referred to - using "*" syntax, following C language convention. - - We emphasize that all the API functions described in this document - are "abstract" calls and that conformant CM implementations may - differ in specific implementation details. - -2. Introduction - - The framework described in this document integrates congestion - management across all applications and transport protocols. The CM - maintains congestion parameters (available aggregate and per-stream - bandwidth, per-receiver round-trip times, etc.) and exports an API - that enables applications to learn about network characteristics, - pass information to the CM, share congestion information with each - other, and schedule data transmissions. This document focuses on - applications and transport protocols with their own independent per- - byte or per-packet sequence number information, and does not require - modifications to the receiver protocol stack. However, the receiving - application must provide feedback to the sending application about - received packets and losses, and the latter is expected to use the CM - API to update CM state. This document does not address networks with - reservations or service differentiation. - - The CM is an end-system module that enables an ensemble of multiple - concurrent streams to perform stable congestion avoidance and - control, and allows applications to easily adapt their transmissions - to prevailing network conditions. It integrates congestion - management across all applications and transport protocols. It - maintains congestion parameters (available aggregate and per-stream - bandwidth, per-receiver round-trip times, etc.) and exports an API - that enables applications to learn about network characteristics, - pass information to the CM, share congestion information with each - other, and schedule data transmissions. When the CM is used, all - data transmissions subject to the CM must be done with the explicit - consent of the CM via this API to ensure proper congestion behavior. - - Systems MAY choose to use CM, and if so they MUST follow this - specification. - - This document focuses on applications and networks where the - following conditions hold: - - - -Balakrishnan, et. al. Standards Track [Page 3] - -RFC 3124 The Congestion Manager June 2001 - - - 1. Applications are well-behaved with their own independent - per-byte or per-packet sequence number information, and use the - CM API to update internal state in the CM. - - 2. Networks are best-effort without service discrimination or - reservations. In particular, it does not address situations - where different streams between the same pair of hosts traverse - paths with differing characteristics. - - The Congestion Manager framework can be extended to support - applications that do not provide their own feedback and to - differentially-served networks. These extensions will be addressed - in later documents. - - The CM is motivated by two main goals: - - (i) Enable efficient multiplexing. Increasingly, the trend on the - Internet is for unicast data senders (e.g., Web servers) to transmit - heterogeneous types of data to receivers, ranging from unreliable - real-time streaming content to reliable Web pages and applets. As a - result, many logically different streams share the same path between - sender and receiver. For the Internet to remain stable, each of - these streams must incorporate control protocols that safely probe - for spare bandwidth and react to congestion. Unfortunately, these - concurrent streams typically compete with each other for network - resources, rather than share them effectively. Furthermore, they do - not learn from each other about the state of the network. Even if - they each independently implement congestion control (e.g., a group - of TCP connections each implementing the algorithms in [Jacobson88, - Allman99]), the ensemble of streams tends to be more aggressive in - the face of congestion than a single TCP connection implementing - standard TCP congestion control and avoidance [Balakrishnan98]. - - (ii) Enable application adaptation to congestion. Increasingly, - popular real-time streaming applications run over UDP using their own - user-level transport protocols for good application performance, but - in most cases today do not adapt or react properly to network - congestion. By implementing a stable control algorithm and exposing - an adaptation API, the CM enables easy application adaptation to - congestion. Applications adapt the data they transmit to the current - network conditions. - - The CM framework builds on recent work on TCP control block sharing - [Touch97], integrated TCP congestion control (TCP-Int) - [Balakrishnan98] and TCP sessions [Padmanabhan98]. [Touch97] - advocates the sharing of some of the state in the TCP control block - to improve transient transport performance and describes sharing - across an ensemble of TCP connections. [Balakrishnan98], - - - -Balakrishnan, et. al. Standards Track [Page 4] - -RFC 3124 The Congestion Manager June 2001 - - - [Padmanabhan98], and [Eggert00] describe several experiments that - quantify the benefits of sharing congestion state, including improved - stability in the face of congestion and better loss recovery. - Integrating loss recovery across concurrent connections significantly - improves performance because losses on one connection can be detected - by noticing that later data sent on another connection has been - received and acknowledged. The CM framework extends these ideas in - two significant ways: (i) it extends congestion management to non-TCP - streams, which are becoming increasingly common and often do not - implement proper congestion management, and (ii) it provides an API - for applications to adapt their transmissions to current network - conditions. For an extended discussion of the motivation for the CM, - its architecture, API, and algorithms, see [Balakrishnan99]; for a - description of an implementation and performance results, see - [Andersen00]. - - The resulting end-host protocol architecture at the sender is shown - in Figure 1. The CM helps achieve network stability by implementing - stable congestion avoidance and control algorithms that are "TCP- - friendly" [Mahdavi98] based on algorithms described in [Allman99]. - However, it does not attempt to enforce proper congestion behavior - for all applications (but it does not preclude a policer on the host - that performs this task). Note that while the policer at the end- - host can use CM, the network has to be protected against compromises - to the CM and the policer at the end hosts, a task that requires - router machinery [Floyd99a]. We do not address this issue further in - this document. - - - - - - - - - - - - - - - - - - - - - - - - -Balakrishnan, et. al. Standards Track [Page 5] - -RFC 3124 The Congestion Manager June 2001 - - - |--------| |--------| |--------| |--------| |--------------| - | HTTP | | FTP | | RTP 1 | | RTP 2 | | | - |--------| |--------| |--------| |--------| | | - | | | ^ | ^ | | - | | | | | | | Scheduler | - | | | | | | |---| | | - | | | |-------|--+->| | | | - | | | | | |<--| | - v v v v | | |--------------| - |--------| |--------| |-------------| | | ^ - | TCP 1 | | TCP 2 | | UDP 1 | | A | | - |--------| |--------| |-------------| | | | - ^ | ^ | | | | |--------------| - | | | | | | P |-->| | - | | | | | | | | | - |---|------+---|--------------|------->| | | Congestion | - | | | | I | | | - v v v | | | Controller | - |-----------------------------------| | | | | - | IP |-->| | | | - |-----------------------------------| | | |--------------| - |---| - - Figure 1 - - The key components of the CM framework are (i) the API, (ii) the - congestion controller, and (iii) the scheduler. The API is (in part) - motivated by the requirements of application-level framing (ALF) - [Clark90], and is described in Section 4. The CM internals (Section - 5) include a congestion controller (Section 5.1) and a scheduler to - orchestrate data transmissions between concurrent streams in a - macroflow (Section 5.2). The congestion controller adjusts the - aggregate transmission rate between sender and receiver based on its - estimate of congestion in the network. It obtains feedback about its - past transmissions from applications themselves via the API. The - scheduler apportions available bandwidth amongst the different - streams within each macroflow and notifies applications when they are - permitted to send data. This document focuses on well-behaved - applications; a future one will describe the sender-receiver protocol - and header formats that will handle applications that do not - incorporate their own feedback to the CM. - -3. CM API - - By convention, the IETF does not treat Application Programming - Interfaces as standards track. However, it is considered important - to have the CM API and CM algorithm requirements in one coherent - document. The following section on the CM API uses the terms MUST, - - - -Balakrishnan, et. al. Standards Track [Page 6] - -RFC 3124 The Congestion Manager June 2001 - - - SHOULD, etc., but the terms are meant to apply within the context of - an implementation of the CM API. The section does not apply to - congestion control implementations in general, only to those - implementations offering the CM API. - - Using the CM API, streams can determine their share of the available - bandwidth, request and have their data transmissions scheduled, - inform the CM about successful transmissions, and be informed when - the CM's estimate of path bandwidth changes. Thus, the CM frees - applications from having to maintain information about the state of - congestion and available bandwidth along any path. - - The function prototypes below follow standard C language convention. - We emphasize that these API functions are abstract calls and - conformant CM implementations may differ in specific details, as long - as equivalent functionality is provided. - - When a new stream is created by an application, it passes some - information to the CM via the cm_open(stream_info) API call. - Currently, stream_info consists of the following information: (i) the - source IP address, (ii) the source port, (iii) the destination IP - address, (iv) the destination port, and (v) the IP protocol number. - -3.1 State maintenance - - 1. Open: All applications MUST call cm_open(stream_info) before - using the CM API. This returns a handle, cm_streamid, for the - application to use for all further CM API invocations for that - stream. If the returned cm_streamid is -1, then the cm_open() - failed and that stream cannot use the CM. - - All other calls to the CM for a stream use the cm_streamid - returned from the cm_open() call. - - 2. Close: When a stream terminates, the application SHOULD invoke - cm_close(cm_streamid) to inform the CM about the termination - of the stream. - - 3. Packet size: cm_mtu(cm_streamid) returns the estimated PMTU of - the path between sender and receiver. Internally, this - information SHOULD be obtained via path MTU discovery - [Mogul90]. It MAY be statically configured in the absence of - such a mechanism. - - - - - - - - -Balakrishnan, et. al. Standards Track [Page 7] - -RFC 3124 The Congestion Manager June 2001 - - -3.2 Data transmission - - The CM accommodates two types of adaptive senders, enabling - applications to dynamically adapt their content based on prevailing - network conditions, and supporting ALF-based applications. - - 1. Callback-based transmission. The callback-based transmission API - puts the stream in firm control of deciding what to transmit at each - point in time. To achieve this, the CM does not buffer any data; - instead, it allows streams the opportunity to adapt to unexpected - network changes at the last possible instant. Thus, this enables - streams to "pull out" and repacketize data upon learning about any - rate change, which is hard to do once the data has been buffered. - The CM must implement a cm_request(i32 cm_streamid) call for streams - wishing to send data in this style. After some time, depending on - the rate, the CM MUST invoke a callback using cmapp_send(), which is - a grant for the stream to send up to PMTU bytes. The callback-style - API is the recommended choice for ALF-based streams. Note that - cm_request() does not take the number of bytes or MTU-sized units as - an argument; each call to cm_request() is an implicit request for - sending up to PMTU bytes. The CM MAY provide an alternate interface, - cm_request(int k). The cmapp_send callback for this request is - granted the right to send up to k PMTU sized segments. Section 4.3 - discusses the time duration for which the transmission grant is - valid, while Section 5.2 describes how these requests are scheduled - and callbacks made. - - 2. Synchronous-style. The above callback-based API accommodates a - class of ALF streams that are "asynchronous." Asynchronous - transmitters do not transmit based on a periodic clock, but do so - triggered by asynchronous events like file reads or captured frames. - On the other hand, there are many streams that are "synchronous" - transmitters, which transmit periodically based on their own internal - timers (e.g., an audio senders that sends at a constant sampling - rate). While CM callbacks could be configured to periodically - interrupt such transmitters, the transmit loop of such applications - is less affected if they retain their original timer-based loop. In - addition, it complicates the CM API to have a stream express the - periodicity and granularity of its callbacks. Thus, the CM MUST - export an API that allows such streams to be informed of changes in - rates using the cmapp_update(u64 newrate, u32 srtt, u32 rttdev) - callback function, where newrate is the new rate in bits per second - for this stream, srtt is the current smoothed round trip time - estimate in microseconds, and rttdev is the smoothed linear deviation - in the round-trip time estimate calculated using the same algorithm - as in TCP [Paxson00]. The newrate value reports an instantaneous - rate calculated, for example, by taking the ratio of cwnd and srtt, - and dividing by the fraction of that ratio allocated to the stream. - - - -Balakrishnan, et. al. Standards Track [Page 8] - -RFC 3124 The Congestion Manager June 2001 - - - In response, the stream MUST adapt its packet size or change its - timer interval to conform to (i.e., not exceed) the allowed rate. Of - course, it may choose not to use all of this rate. Note that the CM - is not on the data path of the actual transmission. - - To avoid unnecessary cmapp_update() callbacks that the application - will only ignore, the CM MUST provide a cm_thresh(float - rate_downthresh, float rate_upthresh, float rtt_downthresh, float - rtt_upthresh) function that a stream can use at any stage in its - execution. In response, the CM SHOULD invoke the callback only when - the rate decreases to less than (rate_downthresh * lastrate) or - increases to more than (rate_upthresh * lastrate), where lastrate is - the rate last notified to the stream, or when the round-trip time - changes correspondingly by the requisite thresholds. This - information is used as a hint by the CM, in the sense the - cmapp_update() can be called even if these conditions are not met. - - The CM MUST implement a cm_query(i32 cm_streamid, u64* rate, u32* - srtt, u32* rttdev) to allow an application to query the current CM - state. This sets the rate variable to the current rate estimate in - bits per second, the srtt variable to the current smoothed round-trip - time estimate in microseconds, and rttdev to the mean linear - deviation. If the CM does not have valid estimates for the - macroflow, it fills in negative values for the rate, srtt, and - rttdev. - - Note that a stream can use more than one of the above transmission - APIs at the same time. In particular, the knowledge of sustainable - rate is useful for asynchronous streams as well as synchronous ones; - e.g., an asynchronous Web server disseminating images using TCP may - use cmapp_send() to schedule its transmissions and cmapp_update() to - decide whether to send a low-resolution or high-resolution image. A - TCP implementation using the CM is described in Section 6.1.1, where - the benefit of the cm_request() callback API for TCP will become - apparent. - - The reader will notice that the basic CM API does not provide an - interface for buffered congestion-controlled transmissions. This is - intentional, since this transmission mode can be implemented using - the callback-based primitive. Section 6.1.2 describes how - congestion-controlled UDP sockets may be implemented using the CM - API. - -3.3 Application notification - - When a stream receives feedback from receivers, it MUST use - cm_update(i32 cm_streamid, u32 nrecd, u32 nlost, u8 lossmode, i32 - rtt) to inform the CM about events such as congestion losses, - - - -Balakrishnan, et. al. Standards Track [Page 9] - -RFC 3124 The Congestion Manager June 2001 - - - successful receptions, type of loss (timeout event, Explicit - Congestion Notification [Ramakrishnan99], etc.) and round-trip time - samples. The nrecd parameter indicates how many bytes were - successfully received by the receiver since the last cm_update call, - while the nrecd parameter identifies how many bytes were received - were lost during the same time period. The rtt value indicates the - round-trip time measured during the transmission of these bytes. The - rtt value must be set to -1 if no valid round-trip sample was - obtained by the application. The lossmode parameter provides an - indicator of how a loss was detected. A value of CM_NO_FEEDBACK - indicates that the application has received no feedback for all its - outstanding data, and is reporting this to the CM. For example, a - TCP that has experienced a timeout would use this parameter to inform - the CM of this. A value of CM_LOSS_FEEDBACK indicates that the - application has experienced some loss, which it believes to be due to - congestion, but not all outstanding data has been lost. For example, - a TCP segment loss detected using duplicate (selective) - acknowledgments or other data-driven techniques fits this category. - A value of CM_EXPLICIT_CONGESTION indicates that the receiver echoed - an explicit congestion notification message. Finally, a value of - CM_NO_CONGESTION indicates that no congestion-related loss has - occurred. The lossmode parameter MUST be reported as a bit-vector - where the bits correspond to CM_NO_FEEDBACK, CM_LOSS_FEEDBACK, - CM_EXPLICIT_CONGESTION, and CM_NO_CONGESTION. Note that over links - (paths) that experience losses for reasons other than congestion, an - application SHOULD inform the CM of losses, with the CM_NO_CONGESTION - field set. - - cm_notify(i32 cm_streamid, u32 nsent) MUST be called when data is - transmitted from the host (e.g., in the IP output routine) to inform - the CM that nsent bytes were just transmitted on a given stream. - This allows the CM to update its estimate of the number of - outstanding bytes for the macroflow and for the stream. - - A cmapp_send() grant from the CM to an application is valid only for - an expiration time, equal to the larger of the round-trip time and an - implementation-dependent threshold communicated as an argument to the - cmapp_send() callback function. The application MUST NOT send data - based on this callback after this time has expired. Furthermore, if - the application decides not to send data after receiving this - callback, it SHOULD call cm_notify(stream_info, 0) to allow the CM to - permit other streams in the macroflow to transmit data. The CM - congestion controller MUST be robust to applications forgetting to - invoke cm_notify(stream_info, 0) correctly, or applications that - crash or disappear after having made a cm_request() call. - - - - - - -Balakrishnan, et. al. Standards Track [Page 10] - -RFC 3124 The Congestion Manager June 2001 - - -3.4 Querying - - If applications wish to learn about per-stream available bandwidth - and round-trip time, they can use the CM's cm_query(i32 cm_streamid, - i64* rate, i32* srtt, i32* rttdev) call, which fills in the desired - quantities. If the CM does not have valid estimates for the - macroflow, it fills in negative values for the rate, srtt, and - rttdev. - -3.5 Sharing granularity - - One of the decisions the CM needs to make is the granularity at which - a macroflow is constructed, by deciding which streams belong to the - same macroflow and share congestion information. The API provides - two functions that allow applications to decide which of their - streams ought to belong to the same macroflow. - - cm_getmacroflow(i32 cm_streamid) returns a unique i32 macroflow - identifier. cm_setmacroflow(i32 cm_macroflowid, i32 cm_streamid) - sets the macroflow of the stream cm_streamid to cm_macroflowid. If - the cm_macroflowid that is passed to cm_setmacroflow() is -1, then a - new macroflow is constructed and this is returned to the caller. - Each call to cm_setmacroflow() overrides the previous macroflow - association for the stream, should one exist. - - The default suggested aggregation method is to aggregate by - destination IP address; i.e., all streams to the same destination - address are aggregated to a single macroflow by default. The - cm_getmacroflow() and cm_setmacroflow() calls can then be used to - change this as needed. We do note that there are some cases where - this may not be optimal, even over best-effort networks. For - example, when a group of receivers are behind a NAT device, the - sender will see them all as one address. If the hosts behind the NAT - are in fact connected over different bottleneck links, some of those - hosts could see worse performance than before. It is possible to - detect such hosts when using delay and loss estimates, although the - specific mechanisms for doing so are beyond the scope of this - document. - - The objective of this interface is to set up sharing of groups not - sharing policy of relative weights of streams in a macroflow. The - latter requires the scheduler to provide an interface to set sharing - policy. However, because we want to support many different - schedulers (each of which may need different information to set - policy), we do not specify a complete API to the scheduler (but see - - - - - - -Balakrishnan, et. al. Standards Track [Page 11] - -RFC 3124 The Congestion Manager June 2001 - - - Section 5.2). A later guideline document is expected to describe a - few simple schedulers (e.g., weighted round-robin, hierarchical - scheduling) and the API they export to provide relative - prioritization. - -4. CM internals - - This section describes the internal components of the CM. It - includes a Congestion Controller and a Scheduler, with well-defined, - abstract interfaces exported by them. - -4.1 Congestion controller - - Associated with each macroflow is a congestion control algorithm; the - collection of all these algorithms comprises the congestion - controller of the CM. The control algorithm decides when and how - much data can be transmitted by a macroflow. It uses application - notifications (Section 4.3) from concurrent streams on the same - macroflow to build up information about the congestion state of the - network path used by the macroflow. - - The congestion controller MUST implement a "TCP-friendly" [Mahdavi98] - congestion control algorithm. Several macroflows MAY (and indeed, - often will) use the same congestion control algorithm but each - macroflow maintains state about the network used by its streams. - - The congestion control module MUST implement the following abstract - interfaces. We emphasize that these are not directly visible to - applications; they are within the context of a macroflow, and are - different from the CM API functions of Section 4. - - - void query(u64 *rate, u32 *srtt, u32 *rttdev): This function - returns the estimated rate (in bits per second) and smoothed - round trip time (in microseconds) for the macroflow. - - - void notify(u32 nsent): This function MUST be used to notify the - congestion control module whenever data is sent by an - application. The nsent parameter indicates the number of bytes - just sent by the application. - - - void update(u32 nsent, u32 nrecd, u32 rtt, u32 lossmode): This - function is called whenever any of the CM streams associated with - a macroflow identifies that data has reached the receiver or has - been lost en route. The nrecd parameter indicates the number of - bytes that have just arrived at the receiver. The nsent - parameter is the sum of the number of bytes just received and the - - - - - -Balakrishnan, et. al. Standards Track [Page 12] - -RFC 3124 The Congestion Manager June 2001 - - - number of bytes identified as lost en route. The rtt parameter is - the estimated round trip time in microseconds during the - transfer. The lossmode parameter provides an indicator of how a - loss was detected (section 4.3). - - Although these interfaces are not visible to applications, the - congestion controller MUST implement these abstract interfaces to - provide for modular inter-operability with different separately- - developed schedulers. - - The congestion control module MUST also call the associated - scheduler's schedule function (section 5.2) when it believes that the - current congestion state allows an MTU-sized packet to be sent. - -4.2 Scheduler - - While it is the responsibility of the congestion control module to - determine when and how much data can be transmitted, it is the - responsibility of a macroflow's scheduler module to determine which - of the streams should get the opportunity to transmit data. - - The Scheduler MUST implement the following interfaces: - - - void schedule(u32 num_bytes): When the congestion control module - determines that data can be sent, the schedule() routine MUST be - called with no more than the number of bytes that can be sent. - In turn, the scheduler MAY call the cmapp_send() function that CM - applications must provide. - - - float query_share(i32 cm_streamid): This call returns the - described stream's share of the total bandwidth available to the - macroflow. This call combined with the query call of the - congestion controller provides the information to satisfy an - application's cm_query() request. - - - void notify(i32 cm_streamid, u32 nsent): This interface is used - to notify the scheduler module whenever data is sent by a CM - application. The nsent parameter indicates the number of bytes - just sent by the application. - - The Scheduler MAY implement many additional interfaces. As - experience with CM schedulers increases, future documents may - make additions and/or changes to some parts of the scheduler - API. - - - - - - - -Balakrishnan, et. al. Standards Track [Page 13] - -RFC 3124 The Congestion Manager June 2001 - - -5. Examples - -5.1 Example applications - - This section describes three possible uses of the CM API by - applications. We describe two asynchronous applications---an - implementation of a TCP sender and an implementation of congestion- - controlled UDP sockets, and a synchronous application---a streaming - audio server. More details of these applications and CM - implementation optimizations for efficient operation are described in - [Andersen00]. - - All applications that use the CM MUST incorporate feedback from the - receiver. For example, it must periodically (typically once or twice - per round trip time) determine how many of its packets arrived at the - receiver. When the source gets this feedback, it MUST use - cm_update() to inform the CM of this new information. This results - in the CM updating ownd and may result in the CM changing its - estimates and calling cmapp_update() of the streams of the macroflow. - - The protocols in this section are examples and suggestions for - implementation, rather than requirements for any conformant - implementation. - -5.1.1 TCP - - A TCP implementation that uses CM should use the cmapp_send() - callback API. TCP only identifies which data it should send upon the - arrival of an acknowledgement or expiration of a timer. As a result, - it requires tight control over when and if new data or - retransmissions are sent. - - When TCP either connects to or accepts a connection from another - host, it performs a cm_open() call to associate the TCP connection - with a cm_streamid. - - Once a connection is established, the CM is used to control the - transmission of outgoing data. The CM eliminates the need for - tracking and reacting to congestion in TCP, because the CM and its - transmission API ensure proper congestion behavior. Loss recovery is - still performed by TCP based on fast retransmissions and recovery as - well as timeouts. In addition, TCP is also modified to have its own - outstanding window (tcp_ownd) estimate. Whenever data segments are - sent from its cmapp_send() callback, TCP updates its tcp_ownd value. - The ownd variable is also updated after each cm_update() call. TCP - also maintains a count of the number of outstanding segments - (pkt_cnt). At any time, TCP can calculate the average packet size - (avg_pkt_size) as tcp_ownd/pkt_cnt. The avg_pkt_size is used by TCP - - - -Balakrishnan, et. al. Standards Track [Page 14] - -RFC 3124 The Congestion Manager June 2001 - - - to help estimate the amount of outstanding data. Note that this is - not needed if the SACK option is used on the connection, since this - information is explicitly available. - - The TCP output routines are modified as follows: - - 1. All congestion window (cwnd) checks are removed. - - 2. When application data is available. The TCP output routines - perform all non-congestion checks (Nagle algorithm, receiver- - advertised window check, etc). If these checks pass, the output - routine queues the data and calls cm_request() for the stream. - - 3. If incoming data or timers result in a loss being detected, the - retransmission is also placed in a queue and cm_request() is - called for the stream. - - 4. The cmapp_send() callback for TCP is set to an output routine. - If any retransmission is enqueued, the routine outputs the - retransmission. Otherwise, the routine outputs as much new data - as the TCP connection state allows. However, the cmapp_send() - never sends more than a single segment per call. This routine - arranges for the other output computations to be done, such as - header and options computations. - - The IP output routine on the host calls cm_notify() when the packets - are actually sent out. Because it does not know which cm_streamid is - responsible for the packet, cm_notify() takes the stream_info as - argument (see Section 4 for what the stream_info should contain). - Because cm_notify() reports the IP payload size, TCP keeps track of - the total header size and incorporates these updates. - - The TCP input routines are modified as follows: - - 1. RTT estimation is done as normal using either timestamps or - Karn's algorithm. Any rtt estimate that is generated is passed to - CM via the cm_update call. - - 2. All cwnd and slow start threshold (ssthresh) updates are - removed. - - 3. Upon the arrival of an ack for new data, TCP computes the value - of in_flight (the amount of data in flight) as snd_max-ack-1 - (i.e., MAX Sequence Sent - Current Ack - 1). TCP then calls - cm_update(streamid, tcp_ownd - in_flight, 0, CM_NO_CONGESTION, - rtt). - - - - - -Balakrishnan, et. al. Standards Track [Page 15] - -RFC 3124 The Congestion Manager June 2001 - - - 4. Upon the arrival of a duplicate acknowledgement, TCP must check - its dupack count (dup_acks) to determine its action. If dup_acks - < 3, the TCP does nothing. If dup_acks == 3, TCP assumes that a - packet was lost and that at least 3 packets arrived to generate - these duplicate acks. Therefore, it calls cm_update(streamid, 4 * - avg_pkt_size, 3 * avg_pkt_size, CM_LOSS_FEEDBACK, rtt). The - average packet size is used since the acknowledgments do not - indicate exactly how much data has reached the other end. Most - TCP implementations interpret a duplicate ACK as an indication - that a full MSS has reached its destination. Once a new ACK is - received, these TCP sender implementations may resynchronize with - TCP receiver. The CM API does not provide a mechanism for TCP to - pass information from this resynchronization. Therefore, TCP can - only infer the arrival of an avg_pkt_size amount of data from each - duplicate ack. TCP also enqueues a retransmission of the lost - segment and calls cm_request(). If dup_acks > 3, TCP assumes that - a packet has reached the other end and caused this ack to be sent. - As a result, it calls cm_update(streamid, avg_pkt_size, - avg_pkt_size, CM_NO_CONGESTION, rtt). - - 5. Upon the arrival of a partial acknowledgment (one that does not - exceed the highest segment transmitted at the time the loss - occurred, as defined in [Floyd99b]), TCP assumes that a packet was - lost and that the retransmitted packet has reached the recipient. - Therefore, it calls cm_update(streamid, 2 * avg_pkt_size, - avg_pkt_size, CM_NO_CONGESTION, rtt). CM_NO_CONGESTION is used - since the loss period has already been reported. TCP also - enqueues a retransmission of the lost segment and calls - cm_request(). - - When the TCP retransmission timer expires, the sender identifies that - a segment has been lost and calls cm_update(streamid, avg_pkt_size, - 0, CM_NO_FEEDBACK, 0) to signify that no feedback has been received - from the receiver and that one segment is sure to have "left the - pipe." TCP also enqueues a retransmission of the lost segment and - calls cm_request(). - -5.1.2 Congestion-controlled UDP - - Congestion-controlled UDP is a useful CM application, which we - describe in the context of Berkeley sockets [Stevens94]. They - provide the same functionality as standard Berkeley UDP sockets, but - instead of immediately sending the data from the kernel packet queue - to lower layers for transmission, the buffered socket implementation - makes calls to the API exported by the CM inside the kernel and gets - callbacks from the CM. When a CM UDP socket is created, it is bound - to a particular stream. Later, when data is added to the packet - queue, cm_request() is called on the stream associated with the - - - -Balakrishnan, et. al. Standards Track [Page 16] - -RFC 3124 The Congestion Manager June 2001 - - - socket. When the CM schedules this stream for transmission, it calls - udp_ccappsend() in the UDP module. This function transmits one MTU - from the packet queue, and schedules the transmission of any - remaining packets. The in-kernel implementation of the CM UDP API - should not require any additional data copies and should support all - standard UDP options. Modifying existing applications to use - congestion-controlled UDP requires the implementation of a new socket - option on the socket. To work correctly, the sender must obtain - feedback about congestion. This can be done in at least two ways: - (i) the UDP receiver application can provide feedback to the sender - application, which will inform the CM of network conditions using - cm_update(); (ii) the UDP receiver implementation can provide - feedback to the sending UDP. Note that this latter alternative - requires changes to the receiver's network stack and the sender UDP - cannot assume that all receivers support this option without explicit - negotiation. - -5.1.3 Audio server - - A typical audio application often has access to the sample in a - multitude of data rates and qualities. The objective of the - application is then to deliver the highest possible quality of audio - (typically the highest data rate) its clients. The selection of - which version of audio to transmit should be based on the current - congestion state of the network. In addition, the source will want - audio delivered to its users at a consistent sampling rate. As a - result, it must send data a regular rate, minimizing delaying - transmissions and reducing buffering before playback. To meet these - requirements, this application can use the synchronous sender API - (Section 4.2). - - When the source first starts, it uses the cm_query() call to get an - initial estimate of network bandwidth and delay. If some other - streams on that macroflow have already been active, then it gets an - initial estimate that is valid; otherwise, it gets negative values, - which it ignores. It then chooses an encoding that does not exceed - these estimates (or, in the case of an invalid estimate, uses - application-specific initial values) and begins transmitting data. - The application also implements the cmapp_update() callback. When - the CM determines that network characteristics have changed, it calls - the application's cmapp_update() function and passes it a new rate - and round-trip time estimate. The application must change its choice - of audio encoding to ensure that it does not exceed these new - estimates. - - - - - - - -Balakrishnan, et. al. Standards Track [Page 17] - -RFC 3124 The Congestion Manager June 2001 - - -5.2 Example congestion control module - - To illustrate the responsibilities of a congestion control module, - the following describes some of the actions of a simple TCP-like - congestion control module that implements Additive Increase - Multiplicative Decrease congestion control (AIMD_CC): - - - query(): AIMD_CC returns the current congestion window (cwnd) - divided by the smoothed rtt (srtt) as its bandwidth estimate. It - returns the smoothed rtt estimate as srtt. - - - notify(): AIMD_CC adds the number of bytes sent to its - outstanding data window (ownd). - - - update(): AIMD_CC subtracts nsent from ownd. If the value of rtt - is non-zero, AIMD_CC updates srtt using the TCP srtt calculation. - If the update indicates that data has been lost, AIMD_CC sets - cwnd to 1 MTU if the loss_mode is CM_NO_FEEDBACK and to cwnd/2 - (with a minimum of 1 MTU) if the loss_mode is CM_LOSS_FEEDBACK or - CM_EXPLICIT_CONGESTION. AIMD_CC also sets its internal ssthresh - variable to cwnd/2. If no loss had occurred, AIMD_CC mimics TCP - slow start and linear growth modes. It increments cwnd by nsent - when cwnd < ssthresh (bounded by a maximum of ssthresh-cwnd) and - by nsent * MTU/cwnd when cwnd > ssthresh. - - - When cwnd or ownd are updated and indicate that at least one MTU - may be transmitted, AIMD_CC calls the CM to schedule a - transmission. - -5.3 Example Scheduler Module - - To clarify the responsibilities of a scheduler module, the following - describes some of the actions of a simple round robin scheduler - module (RR_sched): - - - schedule(): RR_sched schedules as many streams as possible in round - robin fashion. - - - query_share(): RR_sched returns 1/(number of streams in macroflow). - - - notify(): RR_sched does nothing. Round robin scheduling is not - affected by the amount of data sent. - -6. Security Considerations - - The CM provides many of the same services that the congestion control - in TCP provides. As such, it is vulnerable to many of the same - security problems. For example, incorrect reports of losses and - - - -Balakrishnan, et. al. Standards Track [Page 18] - -RFC 3124 The Congestion Manager June 2001 - - - transmissions will give the CM an inaccurate picture of the network's - congestion state. By giving CM a high estimate of congestion, an - attacker can degrade the performance observed by applications. For - example, a stream on a host can arbitrarily slow down any other - stream on the same macroflow, a form of denial of service. - - The more dangerous form of attack occurs when an application gives - the CM a low estimate of congestion. This would cause CM to be - overly aggressive and allow data to be sent much more quickly than - sound congestion control policies would allow. - - [Touch97] describes a number of the security problems that arise with - congestion information sharing. An additional vulnerability (not - covered by [Touch97])) occurs because applications have access - through the CM API to control shared state that will affect other - applications on the same computer. For instance, a poorly designed, - possibly a compromised, or intentionally malicious UDP application - could misuse cm_update() to cause starvation and/or too-aggressive - behavior of others in the macroflow. - -7. References - - [Allman99] Allman, M. and Paxson, V., "TCP Congestion - Control", RFC 2581, April 1999. - - [Andersen00] Balakrishnan, H., System Support for Bandwidth - Management and Content Adaptation in Internet - Applications, Proc. 4th Symp. on Operating Systems - Design and Implementation, San Diego, CA, October - 2000. Available from - http://nms.lcs.mit.edu/papers/cm-osdi2000.html - - [Balakrishnan98] Balakrishnan, H., Padmanabhan, V., Seshan, S., - Stemm, M., and Katz, R., "TCP Behavior of a Busy - Web Server: Analysis and Improvements," Proc. IEEE - INFOCOM, San Francisco, CA, March 1998. - - [Balakrishnan99] Balakrishnan, H., Rahul, H., and Seshan, S., "An - Integrated Congestion Management Architecture for - Internet Hosts," Proc. ACM SIGCOMM, Cambridge, MA, - September 1999. - - [Bradner96] Bradner, S., "The Internet Standards Process --- - Revision 3", BCP 9, RFC 2026, October 1996. - - [Bradner97] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - - - -Balakrishnan, et. al. Standards Track [Page 19] - -RFC 3124 The Congestion Manager June 2001 - - - [Clark90] Clark, D. and Tennenhouse, D., "Architectural - Consideration for a New Generation of Protocols", - Proc. ACM SIGCOMM, Philadelphia, PA, September - 1990. - - [Eggert00] Eggert, L., Heidemann, J., and Touch, J., "Effects - of Ensemble TCP," ACM Computer Comm. Review, - January 2000. - - [Floyd99a] Floyd, S. and Fall, K.," Promoting the Use of End- - to-End Congestion Control in the Internet," - IEEE/ACM Trans. on Networking, 7(4), August 1999, - pp. 458-472. - - [Floyd99b] Floyd, S. and T. Henderson,"The New Reno - Modification to TCP's Fast Recovery Algorithm," RFC - 2582, April 1999. - - [Jacobson88] Jacobson, V., "Congestion Avoidance and Control," - Proc. ACM SIGCOMM, Stanford, CA, August 1988. - - [Mahdavi98] Mahdavi, J. and Floyd, S., "The TCP Friendly - Website," - http://www.psc.edu/networking/tcp_friendly.html - - [Mogul90] Mogul, J. and S. Deering, "Path MTU Discovery," RFC - 1191, November 1990. - - [Padmanabhan98] Padmanabhan, V., "Addressing the Challenges of Web - Data Transport," PhD thesis, Univ. of California, - Berkeley, December 1998. - - [Paxson00] Paxson, V. and M. Allman, "Computing TCP's - Retransmission Timer", RFC 2988, November 2000. - - [Postel81] Postel, J., Editor, "Transmission Control - Protocol", STD 7, RFC 793, September 1981. - - [Ramakrishnan99] Ramakrishnan, K. and Floyd, S., "A Proposal to Add - Explicit Congestion Notification (ECN) to IP," RFC - 2481, January 1999. - - - [Stevens94] Stevens, W., TCP/IP Illustrated, Volume 1. - Addison-Wesley, Reading, MA, 1994. - - [Touch97] Touch, J., "TCP Control Block Interdependence", RFC - 2140, April 1997. - - - -Balakrishnan, et. al. Standards Track [Page 20] - -RFC 3124 The Congestion Manager June 2001 - - -8. Acknowledgments - - We thank David Andersen, Deepak Bansal, and Dorothy Curtis for their - work on the CM design and implementation. We thank Vern Paxson for - his detailed comments, feedback, and patience, and Sally Floyd, Mark - Handley, and Steven McCanne for useful feedback on the CM - architecture. Allison Mankin and Joe Touch provided several useful - comments on previous drafts of this document. - -9. Authors' Addresses - - Hari Balakrishnan - Laboratory for Computer Science - 200 Technology Square - Massachusetts Institute of Technology - Cambridge, MA 02139 - - EMail: hari@lcs.mit.edu - Web: http://nms.lcs.mit.edu/~hari/ - - - Srinivasan Seshan - School of Computer Science - Carnegie Mellon University - 5000 Forbes Ave. - Pittsburgh, PA 15213 - - EMail: srini@cmu.edu - Web: http://www.cs.cmu.edu/~srini/ - - - - - - - - - - - - - - - - - - - - - - -Balakrishnan, et. al. Standards Track [Page 21] - -RFC 3124 The Congestion Manager June 2001 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Balakrishnan, et. al. Standards Track [Page 22] - diff --git a/ext/picotcp/RFC/rfc3150.txt b/ext/picotcp/RFC/rfc3150.txt deleted file mode 100644 index aab7cf0..0000000 --- a/ext/picotcp/RFC/rfc3150.txt +++ /dev/null @@ -1,955 +0,0 @@ - - - - - - -Network Working Group S. Dawkins -Request for Comments: 3150 G. Montenegro -BCP: 48 M . Kojo -Category: Best Current Practice V. Magret - July 2001 - - - End-to-end Performance Implications of Slow Links - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2001). All Rights Reserved. - -Abstract - - This document makes performance-related recommendations for users of - network paths that traverse "very low bit-rate" links. - - "Very low bit-rate" implies "slower than we would like". This - recommendation may be useful in any network where hosts can saturate - available bandwidth, but the design space for this recommendation - explicitly includes connections that traverse 56 Kb/second modem - links or 4.8 Kb/second wireless access links - both of which are - widely deployed. - - This document discusses general-purpose mechanisms. Where - application-specific mechanisms can outperform the relevant general- - purpose mechanism, we point this out and explain why. - - This document has some recommendations in common with RFC 2689, - "Providing integrated services over low-bitrate links", especially in - areas like header compression. This document focuses more on - traditional data applications for which "best-effort delivery" is - appropriate. - - - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 1] - -RFC 3150 PILC - Slow Links July 2001 - - -Table of Contents - - 1.0 Introduction ................................................. 2 - 2.0 Description of Optimizations ................................. 3 - 2.1 Header Compression Alternatives ...................... 3 - 2.2 Payload Compression Alternatives ..................... 5 - 2.3 Choosing MTU sizes ................................... 5 - 2.4 Interactions with TCP Congestion Control [RFC2581] ... 6 - 2.5 TCP Buffer Auto-tuning ............................... 9 - 2.6 Small Window Effects ................................. 10 - 3.0 Summary of Recommended Optimizations ......................... 10 - 4.0 Topics For Further Work ...................................... 12 - 5.0 Security Considerations ...................................... 12 - 6.0 IANA Considerations .......................................... 13 - 7.0 Acknowledgements ............................................. 13 - 8.0 References ................................................... 13 - Authors' Addresses ............................................... 16 - Full Copyright Statement ......................................... 17 - -1.0 Introduction - - The Internet protocol stack was designed to operate in a wide range - of link speeds, and has met this design goal with only a limited - number of enhancements (for example, the use of TCP window scaling as - described in "TCP Extensions for High Performance" [RFC1323] for - very-high-bandwidth connections). - - Pre-World Wide Web application protocols tended to be either - interactive applications sending very little data (e.g., Telnet) or - bulk transfer applications that did not require interactive response - (e.g., File Transfer Protocol, Network News). The World Wide Web has - given us traffic that is both interactive and often "bulky", - including images, sound, and video. - - The World Wide Web has also popularized the Internet, so that there - is significant interest in accessing the Internet over link speeds - that are much "slower" than typical office network speeds. In fact, - a significant proportion of the current Internet users is connected - to the Internet over a relatively slow last-hop link. In future, the - number of such users is likely to increase rapidly as various mobile - devices are foreseen to to be attached to the Internet over slow - wireless links. - - In order to provide the best interactive response for these "bulky" - transfers, implementors may wish to minimize the number of bits - actually transmitted over these "slow" connections. There are two - - - - - -Dawkins, et al. Best Current Practice [Page 2] - -RFC 3150 PILC - Slow Links July 2001 - - - areas that can be considered - compressing the bits that make up the - overhead associated with the connection, and compressing the bits - that make up the payload being transported over the connection. - - In addition, implementors may wish to consider TCP receive window - settings and queuing mechanisms as techniques to improve performance - over low-speed links. While these techniques do not involve protocol - changes, they are included in this document for completeness. - -2.0 Description of Optimizations - - This section describes optimizations which have been suggested for - use in situations where hosts can saturate their links. The next - section summarizes recommendations about the use of these - optimizations. - -2.1 Header Compression Alternatives - - Mechanisms for TCP and IP header compression defined in [RFC1144, - RFC2507, RFC2508, RFC2509, RFC3095] provide the following benefits: - - - Improve interactive response time - - - Decrease header overhead (for a typical dialup MTU of 296 - bytes, the overhead of TCP/IP headers can decrease from about - 13 percent with typical 40-byte headers to 1-1.5 percent with - with 3-5 byte compressed headers, for most packets). This - enables use of small packets for delay-sensitive low data-rate - traffic and good line efficiency for bulk data even with small - segment sizes (for reasons to use a small MTU on slow links, - see section 2.3) - - - Many slow links today are wireless and tend to be significantly - lossy. Header compression reduces packet loss rate over lossy - links (simply because shorter transmission times expose packets - to fewer events that cause loss). - - [RFC1144] header compression is a Proposed Standard for TCP Header - compression that is widely deployed. Unfortunately it is vulnerable - on lossy links, because even a single bit error results in loss of - synchronization between the compressor and decompressor. It uses TCP - timeouts to detect a loss of such synchronization, but these errors - result in loss of data (up to a full TCP window), delay of a full - RTO, and unnecessary slow-start. - - - - - - - -Dawkins, et al. Best Current Practice [Page 3] - -RFC 3150 PILC - Slow Links July 2001 - - - A more recent header compression proposal [RFC2507] includes an - explicit request for retransmission of an uncompressed packet to - allow resynchronization without waiting for a TCP timeout (and - executing congestion avoidance procedures). This works much better - on links with lossy characteristics. - - The above scheme ceases to perform well under conditions as extreme - as those of many cellular links (error conditions of 1e-3 or 1e-2 and - round trip times over 100 ms.). For these cases, the 'Robust Header - Compression' working group has developed ROHC [RFC3095]. Extensions - of ROHC to support compression of TCP headers are also under - development. - - [RFC1323] defines a "TCP Timestamp" option, used to prevent - "wrapping" of the TCP sequence number space on high-speed links, and - to improve TCP RTT estimates by providing unambiguous TCP roundtrip - timings. Use of TCP timestamps prevents header compression, because - the timestamps are sent as TCP options. This means that each - timestamped header has TCP options that differ from the previous - header, and headers with changed TCP options are always sent - uncompressed. In addition, timestamps do not seem to have much of an - impact on RTO estimation [AlPa99]. - - Nevertheless, the ROHC working group is developing schemes to - compress TCP headers, including options such as timestamps and - selective acknowledgements. - - Recommendation: Implement [RFC2507], in particular as it relates to - IPv4 tunnels and Minimal Encapsulation for Mobile IP, as well as TCP - header compression for lossy links and links that reorder packets. - PPP capable devices should implement "IP Header Compression over PPP" - [RFC2509]. Robust Header Compression [RFC3095] is recommended for - extremely slow links with very high error rates (see above), but - implementors should judge if its complexity is justified (perhaps by - the cost of the radio frequency resources). - - [RFC1144] header compression should only be enabled when operating - over reliable "slow" links. - - Use of TCP Timestamps [RFC1323] is not recommended with these - connections, because it complicates header compression. Even though - the Robust Header Compression (ROHC) working group is developing - specifications to remedy this, those mechanisms are not yet fully - developed nor deployed, and may not be generally justifiable. - Furthermore, connections traversing "slow" links do not require - protection against TCP sequence-number wrapping. - - - - - -Dawkins, et al. Best Current Practice [Page 4] - -RFC 3150 PILC - Slow Links July 2001 - - -2.2 Payload Compression Alternatives - - Compression of IP payloads is also desirable on "slow" network links. - "IP Payload Compression Protocol (IPComp)" [RFC2393] defines a - framework where common compression algorithms can be applied to - arbitrary IP segment payloads. - - IP payload compression is something of a niche optimization. It is - necessary because IP-level security converts IP payloads to random - bitstreams, defeating commonly-deployed link-layer compression - mechanisms which are faced with payloads that have no redundant - "information" that can be more compactly represented. - - However, many IP payloads are already compressed (images, audio, - video, "zipped" files being transferred), or are already encrypted - above the IP layer (e.g., SSL [SSL]/TLS [RFC2246]). These payloads - will not "compress" further, limiting the benefit of this - optimization. - - For uncompressed HTTP payload types, HTTP/1.1 [RFC2616] also includes - Content-Encoding and Accept-Encoding headers, supporting a variety of - compression algorithms for common compressible MIME types like - text/plain. This leaves only the HTTP headers themselves - uncompressed. - - In general, application-level compression can often outperform - IPComp, because of the opportunity to use compression dictionaries - based on knowledge of the specific data being compressed. - - Extensive use of application-level compression techniques will reduce - the need for IPComp, especially for WWW users. - - Recommendation: IPComp may optionally be implemented. - -2.3 Choosing MTU Sizes - - There are several points to keep in mind when choosing an MTU for - low-speed links. - - First, if a full-length MTU occupies a link for longer than the - delayed ACK timeout (typically 200 milliseconds, but may be up to 500 - milliseconds), this timeout will cause an ACK to be generated for - every segment, rather than every second segment, as occurs with most - implementations of the TCP delayed ACK algorithm. - - - - - - - -Dawkins, et al. Best Current Practice [Page 5] - -RFC 3150 PILC - Slow Links July 2001 - - - Second, "relatively large" MTUs, which take human-perceptible amounts - of time to be transmitted into the network, create human-perceptible - delays in other flows using the same link. [RFC1144] considers - 100-200 millisecond delays as human-perceptible. The convention of - choosing 296-byte MTUs (with header compression enabled) for dialup - access is a compromise that limits the maximum link occupancy delay - with full-length MTUs close to 200 milliseconds on 9.6 Kb/second - links. - - Third, on last-hop links using a larger link MTU size, and therefore - larger MSS, would allow a TCP sender to increase its congestion - window faster in bytes than when using a smaller MTU size (and a - smaller MSS). However, with a smaller MTU size, and a smaller MSS - size, the congestion window, when measured in segments, increases - more quickly than it would with a larger MSS size. Connections using - smaller MSS sizes are more likely to be able to send enough segments - to generate three duplicate acknowledgements, triggering fast - retransmit/fast recovery when packet losses are encountered. Hence, - a smaller MTU size is useful for slow links with lossy - characteristics. - - Fourth, using a smaller MTU size also decreases the queuing delay of - a TCP flow (and thereby RTT) compared to use of larger MTU size with - the same number of packets in a queue. This means that a TCP flow - using a smaller segment size and traversing a slow link is able to - inflate the congestion window (in number of segments) to a larger - value while experiencing the same queuing delay. - - Finally, some networks charge for traffic on a per-packet basis, not - on a per-kilobyte basis. In these cases, connections using a larger - MTU may be charged less than connections transferring the same number - of bytes using a smaller MTU. - - Recommendation: If it is possible to do so, MTUs should be chosen - that do not monopolize network interfaces for human-perceptible - amounts of time, and implementors should not chose MTUs that will - occupy a network interface for significantly more than 100-200 - milliseconds. - -2.4 Interactions with TCP Congestion Control [RFC2581] - - In many cases, TCP connections that traverse slow links have the slow - link as an "access" link, with higher-speed links in use for most of - the connection path. One common configuration might be a laptop - computer using dialup access to a terminal server (a last-hop - router), with an HTTP server on a high-speed LAN "behind" the - terminal server. - - - - -Dawkins, et al. Best Current Practice [Page 6] - -RFC 3150 PILC - Slow Links July 2001 - - - In this case, the HTTP server may be able to place packets on its - directly-attached high-speed LAN at a higher rate than the last-hop - router can forward them on the low-speed link. When the last-hop - router falls behind, it will be unable to buffer the traffic intended - for the low-speed link, and will become a point of congestion and - begin to drop the excess packets. In particular, several packets may - be dropped in a single transmission window when initial slow start - overshoots the last-hop router buffer. - - Although packet loss is occurring, it isn't detected at the TCP - sender until one RTT time after the router buffer space is exhausted - and the first packet is dropped. This late congestion signal allows - the congestion window to increase up to double the size it was at the - time the first packet was dropped at the router. - - If the link MTU is large enough to take more than the delayed ACK - timeout interval to transmit a packet, an ACK is sent for every - segment and the congestion window is doubled in a single RTT. If a - smaller link MTU is in use and delayed ACKs can be utilized, the - congestion window increases by a factor of 1.5 in one RTT. In both - cases the sender continues transmitting packets well beyond the - congestion point of the last-hop router, resulting in multiple packet - losses in a single window. - - The self-clocking nature of TCP's slow start and congestion avoidance - algorithms prevent this buffer overrun from continuing. In addition, - these algorithms allow senders to "probe" for available bandwidth - - cycling through an increasing rate of transmission until loss occurs, - followed by a dramatic (50-percent) drop in transmission rate. This - happens when a host directly connected to a low-speed link offers an - advertised window that is unrealistically large for the low-speed - link. During the congestion avoidance phase the peer host continues - to probe for available bandwidth, trying to fill the advertised - window, until packet loss occurs. - - The same problems may also exist when a sending host is directly - connected to a slow link as most slow links have some local buffer in - the link interface. This link interface buffer is subject to - overflow exactly in the same way as the last-hop router buffer. - - When a last-hop router with a small number of buffers per outbound - link is used, the first buffer overflow occurs earlier than it would - if the router had a larger number of buffers. Subsequently with a - smaller number of buffers the periodic packet losses occur more - frequently during congestion avoidance, when the sender probes for - available bandwidth. - - - - - -Dawkins, et al. Best Current Practice [Page 7] - -RFC 3150 PILC - Slow Links July 2001 - - - The most important responsibility of router buffers is to absorb - bursts. Too few buffers (for example, only three buffers per - outbound link as described in [RFC2416]) means that routers will - overflow their buffer pools very easily and are unlikely to absorb - even a very small burst. When a larger number of router buffers are - allocated per outbound link, the buffer space does not overflow as - quickly but the buffers are still likely to become full due to TCP's - default behavior. A larger number of router buffers leads to longer - queuing delays and a longer RTT. - - If router queues become full before congestion is signaled or remain - full for long periods of time, this is likely to result in "lock- - out", where a single connection or a few connections occupy the - router queue space, preventing other connections from using the link - [RFC2309], especially when a tail drop queue management discipline is - being used. - - Therefore, it is essential to have a large enough number of buffers - in routers to be able to absorb data bursts, but keep the queues - normally small. In order to achieve this it has been recommended in - [RFC2309] that an active queue management mechanism, like Random - Early Detection (RED) [RED93], should be implemented in all Internet - routers, including the last-hop routers in front of a slow link. It - should also be noted that RED requires a sufficiently large number of - router buffers to work properly. In addition, the appropriate - parameters of RED on a last-hop router connected to a slow link will - likely deviate from the defaults recommended. - - Active queue management mechanism do not eliminate packet drops but, - instead, drop packets at earlier stage to solve the full-queue - problem for flows that are responsive to packet drops as congestion - signal. Hosts that are directly connected to low-speed links may - limit the receive windows they advertise in order to lower or - eliminate the number of packet drops in a last-hop router. When - doing so one should, however, take care that the advertised window is - large enough to allow full utilization of the last-hop link capacity - and to allow triggering fast retransmit, when a packet loss is - encountered. This recommendation takes two forms: - - - Modern operating systems use relatively large default TCP receive - buffers compared to what is required to fully utilize the link - capacity of low-speed links. Users should be able to choose the - default receive window size in use - typically a system-wide - parameter. (This "choice" may be as simple as "dial-up access/LAN - access" on a dialog box - this would accommodate many environments - without requiring hand-tuning by experienced network engineers.) - - - - - -Dawkins, et al. Best Current Practice [Page 8] - -RFC 3150 PILC - Slow Links July 2001 - - - - Application developers should not attempt to manually manage - network bandwidth using socket buffer sizes. Only in very rare - circumstances will an application actually know both the bandwidth - and delay of a path and be able to choose a suitably low (or high) - value for the socket buffer size to obtain good network - performance. - - This recommendation is not a general solution for any network path - that might involve a slow link. Instead, this recommendation is - applicable in environments where the host "knows" it is always - connected to other hosts via "slow links". For hosts that may - connect to other host over a variety of links (e.g., dial-up laptop - computers with LAN-connected docking stations), buffer auto-tuning - for the receive buffer is a more reasonable recommendation, and is - discussed below. - -2.5 TCP Buffer Auto-tuning - - [SMM98] recognizes a tension between the desire to allocate "large" - TCP buffers, so that network paths are fully utilized, and a desire - to limit the amount of memory dedicated to TCP buffers, in order to - efficiently support large numbers of connections to hosts over - network paths that may vary by six orders of magnitude. - - The technique proposed is to dynamically allocate TCP buffers, based - on the current congestion window, rather than attempting to - preallocate TCP buffers without any knowledge of the network path. - - This proposal results in receive buffers that are appropriate for the - window sizes in use, and send buffers large enough to contain two - windows of segments, so that SACK and fast recovery can recover - losses without forcing the connection to use lengthy retransmission - timeouts. - - While most of the motivation for this proposal is given from a - server's perspective, hosts that connect using multiple interfaces - with markedly-different link speeds may also find this kind of - technique useful. This is true in particular with slow links, which - are likely to dominate the end-to-end RTT. If the host is connected - only via a single slow link interface at a time, it is fairly easy to - (dynamically) adjust the receive window (and thus the advertised - window) to a value appropriate for the slow last-hop link with known - bandwidth and delay characteristics. - - Recommendation: If a host is sometimes connected via a slow link but - the host is also connected using other interfaces with markedly- - different link speeds, it may use receive buffer auto-tuning to - adjust the advertised window to an appropriate value. - - - -Dawkins, et al. Best Current Practice [Page 9] - -RFC 3150 PILC - Slow Links July 2001 - - -2.6 Small Window Effects - - If a TCP connection stabilizes with a congestion window of only a few - segments (as could be expected on a "slow" link), the sender isn't - sending enough segments to generate three duplicate acknowledgements, - triggering fast retransmit and fast recovery. This means that a - retransmission timeout is required to repair the loss - dropping the - TCP connection to a congestion window with only one segment. - - [TCPB98] and [TCPF98] observe that (in studies of network trace - datasets) it is relatively common for TCP retransmission timeouts to - occur even when some duplicate acknowledgements are being sent. The - challenge is to use these duplicate acknowledgements to trigger fast - retransmit/fast recovery without injecting traffic into the network - unnecessarily - and especially not injecting traffic in ways that - will result in instability. - - The "Limited Transmit" algorithm [RFC3042] suggests sending a new - segment when the first and second duplicate acknowledgements are - received, so that the receiver is more likely to be able to continue - to generate duplicate acknowledgements until the TCP retransmit - threshold is reached, triggering fast retransmit and fast recovery. - When the congestion window is small, this is very useful in assisting - fast retransmit and fast recovery to recover from a packet loss - without using a retransmission timeout. We note that a maximum of - two additional new segments will be sent before the receiver sends - either a new acknowledgement advancing the window or two additional - duplicate acknowledgements, triggering fast retransmit/fast recovery, - and that these new segments will be acknowledgement-clocked, not - back-to-back. - - Recommendation: Limited Transmit should be implemented in all hosts. - -3.0 Summary of Recommended Optimizations - - This section summarizes our recommendations regarding the previous - standards-track mechanisms, for end nodes that are connected via a - slow link. - - Header compression should be implemented. [RFC1144] header - compression can be enabled over robust network links. [RFC2507] - should be used over network connections that are expected to - experience loss due to corruption as well as loss due to congestion. - For extremely lossy and slow links, implementors should evaluate ROHC - [RFC3095] as a potential solution. [RFC1323] TCP timestamps must be - turned off because (1) their protection against TCP sequence number - wrapping is unjustified for slow links, and (2) they complicate TCP - header compression. - - - -Dawkins, et al. Best Current Practice [Page 10] - -RFC 3150 PILC - Slow Links July 2001 - - - IP Payload Compression [RFC2393] should be implemented, although - compression at higher layers of the protocol stack (for example [RFC - 2616]) may make this mechanism less useful. - - For HTTP/1.1 environments, [RFC2616] payload compression should be - implemented and should be used for payloads that are not already - compressed. - - Implementors should choose MTUs that don't monopolize network - interfaces for more than 100-200 milliseconds, in order to limit the - impact of a single connection on all other connections sharing the - network interface. - - Use of active queue management is recommended on last-hop routers - that provide Internet access to host behind a slow link. In - addition, number of router buffers per slow link should be large - enough to absorb concurrent data bursts from more than a single flow. - To absorb concurrent data bursts from two or three TCP senders with a - typical data burst of three back-to-back segments per sender, at - least six (6) or nine (9) buffers are needed. Effective use of - active queue management is likely to require even larger number of - buffers. - - Implementors should consider the possibility that a host will be - directly connected to a low-speed link when choosing default TCP - receive window sizes. - - Application developers should not attempt to manually manage network - bandwidth using socket buffer sizes as only in very rare - circumstances an application will be able to choose a suitable value - for the socket buffer size to obtain good network performance. - - Limited Transmit [RFC3042] should be implemented in all end hosts as - it assists in triggering fast retransmit when congestion window is - small. - - All of the mechanisms described above are stable standards-track RFCs - (at Proposed Standard status, as of this writing). - - In addition, implementors may wish to consider TCP buffer auto- - tuning, especially when the host system is likely to be used with a - wide variety of access link speeds. This is not a standards-track - TCP mechanism but, as it is an operating system implementation issue, - it does not need to be standardized. - - Of the above mechanisms, only Header Compression (for IP and TCP) may - cease to work in the presence of end-to-end IPSEC. However, - [RFC3095] does allow compressing the ESP header. - - - -Dawkins, et al. Best Current Practice [Page 11] - -RFC 3150 PILC - Slow Links July 2001 - - -4.0 Topics For Further Work - - In addition to the standards-track mechanisms discussed above, there - are still opportunities to improve performance over low-speed links. - - "Sending fewer bits" is an obvious response to slow link speeds. The - now-defunct HTTP-NG proposal [HTTP-NG] replaced the text-based HTTP - header representation with a binary representation for compactness. - However, HTTP-NG is not moving forward and HTTP/1.1 is not being - enhanced to include a more compact HTTP header representation. - Instead, the Wireless Application Protocol (WAP) Forum has opted for - the XML-based Wireless Session Protocol [WSP], which includes a - compact header encoding mechanism. - - It would be nice to agree on a more compact header representation - that will be used by all WWW communities, not only the wireless WAN - community. Indeed, general XML content encodings have been proposed - [Millau], although they are not yet widely adopted. - - We note that TCP options which change from segment to segment - effectively disable header compression schemes deployed today, - because there's no way to indicate that some fields in the header are - unchanged from the previous segment, while other fields are not. The - Robust Header Compression working group is developing such schemes - for TCP options such as timestamps and selective acknowledgements. - Hopefully, documents subsequent to [RFC3095] will define such - specifications. - - Another effort worth following is that of 'Delta Encoding'. Here, - clients that request a slightly modified version of some previously - cached resource would receive a succinct description of the - differences, rather than the entire resource [HTTP-DELTA]. - -5.0 Security Considerations - - All recommendations included in this document are stable standards- - track RFCs (at Proposed Standard status, as of this writing) or - otherwise do not suggest any changes to any protocol. With the - exception of Van Jacobson compression [RFC1144] and [RFC2507, - RFC2508, RFC2509], all other mechanisms are applicable to TCP - connections protected by end-to-end IPSec. This includes ROHC - [RFC3095], albeit partially, because even though it can compress the - outermost ESP header to some extent, encryption still renders any - payload data uncompressible (including any subsequent protocol - headers). - - - - - - -Dawkins, et al. Best Current Practice [Page 12] - -RFC 3150 PILC - Slow Links July 2001 - - -6.0 IANA Considerations - - This document is a pointer to other, existing IETF standards. There - are no new IANA considerations. - -7.0 Acknowledgements - - This recommendation has grown out of "Long Thin Networks" [RFC2757], - which in turn benefited from work done in the IETF TCPSAT working - group. - -8.0 References - - [AlPa99] Mark Allman and Vern Paxson, "On Estimating End-to-End - Network Path Properties", in ACM SIGCOMM 99 Proceedings, - 1999. - - [HTTP-DELTA] J. Mogul, et al., "Delta encoding in HTTP", Work in - Progress. - - [HTTP-NG] Mike Spreitzer, Bill Janssen, "HTTP 'Next Generation'", - 9th International WWW Conference, May, 2000. Also - available as: http://www.www9.org/w9cdrom/60/60.html - - [Millau] Marc Girardot, Neel Sundaresan, "Millau: an encoding - format for efficient representation and exchange of XML - over the Web", 9th International WWW Conference, May, - 2000. Also available as: - http://www.www9.org/w9cdrom/154/154.html - - [PAX97] Paxson, V., "End-to-End Internet Packet Dynamics", 1997, - in SIGCOMM 97 Proceedings, available as: - http://www.acm.org/sigcomm/ccr/archive/ccr-toc/ccr-toc- - 97.html - - [RED93] Floyd, S., and Jacobson, V., Random Early Detection - gateways for Congestion Avoidance, IEEE/ACM Transactions - on Networking, V.1 N.4, August 1993, pp. 397-413. Also - available from http://ftp.ee.lbl.gov/floyd/red.html. - - [RFC1144] Jacobson, V., "Compressing TCP/IP Headers for Low-Speed - Serial Links", RFC 1144, February 1990. - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 13] - -RFC 3150 PILC - Slow Links July 2001 - - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol: Version - 1.0", RFC 2246, January 1999. - - [RFC2309] Braden, R., Clark, D., Crowcroft, J., Davie, B., - Deering, S., Estrin, D., Floyd, S., Jacobson, V., - Minshall, G., Partridge, C., Peterson, L., Ramakrishnan, - K., Shenker, S., Wroclawski, J. and L. Zhang, - "Recommendations on Queue Management and Congestion - Avoidance in the Internet", RFC 2309, April 1998. - - [RFC2393] Shacham, A., Monsour, R., Pereira, R. and M. Thomas, "IP - Payload Compression Protocol (IPComp)", RFC 2393, - December 1998. - - [RFC2401] Kent, S. and R. Atkinson, "Security Architecture for the - Internet Protocol", RFC 2401, November 1998. - - [RFC2416] Shepard, T. and C. Partridge, "When TCP Starts Up With - Four Packets Into Only Three Buffers", RFC 2416, - September 1998. - - [RFC2507] Degermark, M., Nordgren, B. and S. Pink, "IP Header - Compression", RFC 2507, February 1999. - - [RFC2508] Casner, S. and V. Jacobson. "Compressing IP/UDP/RTP - Headers for Low-Speed Serial Links", RFC 2508, February - 1999. - - [RFC2509] Engan, M., Casner, S. and C. Bormann, "IP Header - Compression over PPP", RFC 2509, February 1999. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., - Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext - Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. - - [RFC2757] Montenegro, G., Dawkins, S., Kojo, M., Magret, V., and - N. Vaidya, "Long Thin Networks", RFC 2757, January 2000. - - [RFC3042] Allman, M., Balakrishnan, H. and S. Floyd, "Enhancing - TCP's Loss Recovery Using Limited Transmit", RFC 3042, - January 2001. - - - - -Dawkins, et al. Best Current Practice [Page 14] - -RFC 3150 PILC - Slow Links July 2001 - - - [RFC3095] Bormann, C., Burmeister, C., Degermark, M., Fukushima, - H., Hannu, H., Jonsson, L-E., Hakenberg, R., Koren, T., - Le, K., Liu, Z., Martensson, A., Miyazaki, A., Svanbro, - K., Wiebke, T., Yoshimura, T. and H. Zheng, "RObust - Header Compression (ROHC): Framework and four Profiles: - RTP, UDP ESP and uncompressed", RFC 3095, July 2001. - - [SMM98] Jeffrey Semke, Matthew Mathis, and Jamshid Mahdavi, - "Automatic TCP Buffer Tuning", in ACM SIGCOMM 98 - Proceedings 1998. Available from - http://www.acm.org/sigcomm/sigcomm98/tp/abs_26.html. - - [SSL] Alan O. Freier, Philip Karlton, Paul C. Kocher, The SSL - Protocol: Version 3.0, March 1996. (Expired Internet- - Draft, available from - http://home.netscape.com/eng/ssl3/ssl-toc.html) - - [TCPB98] Hari Balakrishnan, Venkata N. Padmanabhan, Srinivasan - Seshan, Mark Stemm, Randy H. Katz, "TCP Behavior of a - Busy Internet Server: Analysis and Improvements", IEEE - Infocom, March 1998. Available from: - http://www.cs.berkeley.edu/~hari/papers/infocom98.ps.gz - - [TCPF98] Dong Lin and H.T. Kung, "TCP Fast Recovery Strategies: - Analysis and Improvements", IEEE Infocom, March 1998. - Available from: - http://www.eecs.harvard.edu/networking/papers/ infocom- - tcp-final-198.pdf - - [WSP] Wireless Application Protocol Forum, "WAP Wireless - Session Protocol Specification", approved 4 May, 2000, - available from - http://www1.wapforum.org/tech/documents/WAP-203-WSP- - 20000504-a.pdf. (informative reference). - - - - - - - - - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 15] - -RFC 3150 PILC - Slow Links July 2001 - - -Authors' Addresses - - Questions about this document may be directed to: - - Spencer Dawkins - Fujitsu Network Communications - 2801 Telecom Parkway - Richardson, Texas 75082 - - Phone: +1-972-479-3782 - EMail: spencer.dawkins@fnc.fujitsu.com - - - Gabriel Montenegro - Sun Microsystems Laboratories, Europe - 29, chemin du Vieux Chene - 38240 Meylan, FRANCE - - Phone: +33 476 18 80 45 - EMail: gab@sun.com - - - Markku Kojo - Department of Computer Science - University of Helsinki - P.O. Box 26 (Teollisuuskatu 23) - FIN-00014 HELSINKI - Finland - - Phone: +358-9-1914-4179 - Fax: +358-9-1914-4441 - EMail: kojo@cs.helsinki.fi - - - Vincent Magret - Alcatel Internetworking, Inc. - 26801 W. Agoura road - Calabasas, CA, 91301 - - Phone: +1 818 878 4485 - EMail: vincent.magret@alcatel.com - - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 16] - -RFC 3150 PILC - Slow Links July 2001 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 17] - diff --git a/ext/picotcp/RFC/rfc3155.txt b/ext/picotcp/RFC/rfc3155.txt deleted file mode 100644 index 3dd5e91..0000000 --- a/ext/picotcp/RFC/rfc3155.txt +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group S. Dawkins -Request for Comments: 3155 G. Montenegro -BCP: 50 M. Kojo -Category: Best Current Practice V. Magret - N. Vaidya - August 2001 - - - End-to-end Performance Implications of Links with Errors - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2001). All Rights Reserved. - -Abstract - - This document discusses the specific TCP mechanisms that are - problematic in environments with high uncorrected error rates, and - discusses what can be done to mitigate the problems without - introducing intermediate devices into the connection. - -Table of Contents - - 1.0 Introduction ............................................. 2 - 1.1 Should you be reading this recommendation? ........... 3 - 1.2 Relationship of this recommendation to PEPs ........... 4 - 1.3 Relationship of this recommendation to Link Layer - Mechanisms............................................. 4 - 2.0 Errors and Interactions with TCP Mechanisms .............. 5 - 2.1 Slow Start and Congestion Avoidance [RFC2581] ......... 5 - 2.2 Fast Retransmit and Fast Recovery [RFC2581] ........... 6 - 2.3 Selective Acknowledgements [RFC2018, RFC2883] ......... 7 - 3.0 Summary of Recommendations ............................... 8 - 4.0 Topics For Further Work .................................. 9 - 4.1 Achieving, and maintaining, large windows ............. 10 - 5.0 Security Considerations .................................. 11 - 6.0 IANA Considerations ...................................... 11 - 7.0 Acknowledgements ......................................... 11 - References ................................................... 11 - Authors' Addresses ........................................... 14 - Full Copyright Statement ..................................... 16 - - - - -Dawkins, et al. Best Current Practice [Page 1] - -RFC 3155 PILC - Links with Errors August 2001 - - -1.0 Introduction - - The rapidly-growing Internet is being accessed by an increasingly - wide range of devices over an increasingly wide variety of links. At - least some of these links do not provide the degree of reliability - that hosts expect, and this expansion into unreliable links causes - some Internet protocols, especially TCP [RFC793], to perform poorly. - - Specifically, TCP congestion control [RFC2581], while appropriate for - connections that lose traffic primarily because of congestion and - buffer exhaustion, interacts badly with uncorrected errors when TCP - connections traverse links with high uncorrected error rates. The - result is that sending TCPs may spend an excessive amount of time - waiting for acknowledgement that do not arrive, and then, although - these losses are not due to congestion-related buffer exhaustion, the - sending TCP transmits at substantially reduced traffic levels as it - probes the network to determine "safe" traffic levels. - - This document does not address issues with other transport protocols, - for example, UDP. - - Congestion avoidance in the Internet is based on an assumption that - most packet losses are due to congestion. TCP's congestion avoidance - strategy treats the absence of acknowledgement as a congestion - signal. This has worked well since it was introduced in 1988 [VJ- - DCAC], because most links and subnets have relatively low error rates - in normal operation, and congestion is the primary cause of loss in - these environments. However, links and subnets that do not enjoy low - uncorrected error rates are becoming more prevalent in parts of the - Internet. In particular, these include terrestrial and satellite - wireless links. Users relying on traffic traversing these links may - see poor performance because their TCP connections are spending - excessive time in congestion avoidance and/or slow start procedures - triggered by packet losses due to transmission errors. - - The recommendations in this document aim at improving utilization of - available path capacity over such high error-rate links in ways that - do not threaten the stability of the Internet. - - Applications use TCP in very different ways, and these have - interactions with TCP's behavior [RFC2861]. Nevertheless, it is - possible to make some basic assumptions about TCP flows. - Accordingly, the mechanisms discussed here are applicable to all uses - of TCP, albeit in varying degrees according to different scenarios - (as noted where appropriate). - - - - - - -Dawkins, et al. Best Current Practice [Page 2] - -RFC 3155 PILC - Links with Errors August 2001 - - - This recommendation is based on the explicit assumption that major - changes to the entire installed base of routers and hosts are not a - practical possibility. This constrains any changes to hosts that are - directly affected by errored links. - -1.1 Should you be reading this recommendation? - - All known subnetwork technologies provide an "imperfect" subnetwork - service - the bit error rate is non-zero. But there's no obvious way - for end stations to tell the difference between packets discarded due - to congestion and losses due to transmission errors. - - If a directly-attached subnetwork is reporting transmission errors to - a host, these reports matter, but we can't rely on explicit - transmission error reports to both hosts. - - Another way of deciding if a subnetwork should be considered to have - a "high error rate" is by appealing to mathematics. - - An approximate formula for the TCP Reno response function is given in - [PFTK98]: - - s - T = -------------------------------------------------- - RTT*sqrt(2p/3) + tRTO*(3*sqrt(3p/8))*p*(1 + 32p**2) - - where - - T = the sending rate in bytes per second - s = the packet size in bytes - RTT = round-trip time in seconds - tRTO = TCP retransmit timeout value in seconds - p = steady-state packet loss rate - - If one plugs in an observed packet loss rate, does the math and then - sees predicted bandwidth utilization that is greater than the link - speed, the connection will not benefit from recommendations in this - document, because the level of packet losses being encountered won't - affect the ability of TCP to utilize the link. If, however, the - predicted bandwidth is less than the link speed, packet losses are - affecting the ability of TCP to utilize the link. - - If further investigation reveals a subnetwork with significant - transmission error rates, the recommendations in this document will - improve the ability of TCP to utilize the link. - - - - - - -Dawkins, et al. Best Current Practice [Page 3] - -RFC 3155 PILC - Links with Errors August 2001 - - - A few caveats are in order, when doing this calculation: - - (1) the RTT is the end-to-end RTT, not the link RTT. - (2) Max(1.0, 4*RTT) can be substituted as a simplification for - tRTO. - (3) losses may be bursty - a loss rate measured over an interval - that includes multiple bursty loss events may understate the - impact of these loss events on the sending rate. - -1.2 Relationship of this recommendation to PEPs - - This document discusses end-to-end mechanisms that do not require - TCP-level awareness by intermediate nodes. This places severe - limitations on what the end nodes can know about the nature of losses - that are occurring between the end nodes. Attempts to apply - heuristics to distinguish between congestion and transmission error - have not been successful [BV97, BV98, BV98a]. This restriction is - relaxed in an informational document on Performance Enhancing Proxies - (PEPs) [RFC3135]. Because PEPs can be placed on boundaries where - network characteristics change dramatically, PEPs have an additional - opportunity to improve performance over links with uncorrected - errors. - - However, generalized use of PEPs contravenes the end-to-end principle - and is highly undesirable given their deleterious implications, which - include the following: lack of fate sharing (a PEP adds a third point - of failure besides the endpoints themselves), end-to-end reliability - and diagnostics, preventing end-to-end security (particularly network - layer security such as IPsec), mobility (handoffs are much more - complex because state must be transferred), asymmetric routing (PEPs - typically require being on both the forward and reverse paths of a - connection), scalability (PEPs add more state to maintain), QoS - transparency and guarantees. - - Not every type of PEP has all the drawbacks listed above. - Nevertheless, the use of PEPs may have very serious consequences - which must be weighed carefully. - -1.3 Relationship of this recommendation to Link Layer Mechanisms - - This recommendation is for use with TCP over subnetwork technologies - (link layers) that have already been deployed. Subnetworks that are - intended to carry Internet protocols, but have not been completely - specified are the subject of a best common practices (BCP) document - which has been developed or is under development by the Performance - - - - - - -Dawkins, et al. Best Current Practice [Page 4] - -RFC 3155 PILC - Links with Errors August 2001 - - - Implications of Link Characteristics WG (PILC) [PILC-WEB]. This last - document is aimed at designers who still have the opportunity to - reduce the number of uncorrected errors TCP will encounter. - -2.0 Errors and Interactions with TCP Mechanisms - - A TCP sender adapts its use of network path capacity based on - feedback from the TCP receiver. As TCP is not able to distinguish - between losses due to congestion and losses due to uncorrected - errors, it is not able to accurately determine available path - capacity in the presence of significant uncorrected errors. - -2.1 Slow Start and Congestion Avoidance [RFC2581] - - Slow Start and Congestion Avoidance [RFC2581] are essential to the - current stability of the Internet. These mechanisms were designed to - accommodate networks that do not provide explicit congestion - notification. Although experimental mechanisms such as [RFC2481] are - moving in the direction of explicit congestion notification, the - effect of ECN on ECN-aware TCPs is essentially the same as the effect - of implicit congestion notification through congestion-related loss, - except that ECN provides this notification before packets are lost, - and must then be retransmitted. - - TCP connections experiencing high error rates on their paths interact - badly with Slow Start and with Congestion Avoidance, because high - error rates make the interpretation of losses ambiguous - the sender - cannot know whether detected losses are due to congestion or to data - corruption. TCP makes the "safe" choice and assumes that the losses - are due to congestion. - - - Whenever sending TCPs receive three out-of-order - acknowledgement, they assume the network is mildly congested - and invoke fast retransmit/fast recovery (described below). - - - Whenever TCP's retransmission timer expires, the sender assumes - that the network is congested and invokes slow start. - - - Less-reliable link layers often use small link MTUs. This - slows the rate of increase in the sender's window size during - slow start, because the sender's window is increased in units - of segments. Small link MTUs alone don't improve reliability. - Path MTU discovery [RFC1191] must also be used to prevent - fragmentation. Path MTU discovery allows the most rapid - opening of the sender's window size during slow start, but a - number of round trips may still be required to open the window - completely. - - - - -Dawkins, et al. Best Current Practice [Page 5] - -RFC 3155 PILC - Links with Errors August 2001 - - - Recommendation: Any standards-conformant TCP will implement Slow - Start and Congestion Avoidance, which are MUSTs in STD 3 [RFC1122]. - Recommendations in this document will not interfere with these - mechanisms. - -2.2 Fast Retransmit and Fast Recovery [RFC2581] - - TCP provides reliable delivery of data as a byte-stream to an - application, so that when a segment is lost (whether due to either - congestion or transmission loss), the receiver TCP implementation - must wait to deliver data to the receiving application until the - missing data is received. The receiver TCP implementation detects - missing segments by segments arriving with out-of-order sequence - numbers. - - TCPs should immediately send an acknowledgement when data is received - out-of-order [RFC2581], providing the next expected sequence number - with no delay, so that the sender can retransmit the required data as - quickly as possible and the receiver can resume delivery of data to - the receiving application. When an acknowledgement carries the same - expected sequence number as an acknowledgement that has already been - sent for the last in-order segment received, these acknowledgement - are called "duplicate ACKs". - - Because IP networks are allowed to reorder packets, the receiver may - send duplicate acknowledgments for segments that arrive out of order - due to routing changes, link-level retransmission, etc. When a TCP - sender receives three duplicate ACKs, fast retransmit [RFC2581] - allows it to infer that a segment was lost. The sender retransmits - what it considers to be this lost segment without waiting for the - full retransmission timeout, thus saving time. - - After a fast retransmit, a sender halves its congestion window and - invokes the fast recovery [RFC2581] algorithm, whereby it invokes - congestion avoidance from a halved congestion window, but does not - invoke slow start from a one-segment congestion window as it would do - after a retransmission timeout. As the sender is still receiving - dupacks, it knows the receiver is receiving packets sent, so the full - reduction after a timeout when no communication has been received is - not called for. This relatively safe optimization also saves time. - - It is important to be realistic about the maximum throughput that TCP - can have over a connection that traverses a high error-rate link. In - general, TCP will increase its congestion window beyond the delay- - bandwidth product. TCP's congestion avoidance strategy is additive- - increase, multiplicative-decrease, which means that if additional - errors are encountered before the congestion window recovers - completely from a 50-percent reduction, the effect can be a "downward - - - -Dawkins, et al. Best Current Practice [Page 6] - -RFC 3155 PILC - Links with Errors August 2001 - - - spiral" of the congestion window due to additional 50-percent - reductions. Even using Fast Retransmit/Fast Recovery, the sender - will halve the congestion window each time a window contains one or - more segments that are lost, and will re-open the window by one - additional segment for each congestion window's worth of - acknowledgement received. - - If a connection's path traverses a link that loses one or more - segments during this recovery period, the one-half reduction takes - place again, this time on a reduced congestion window - and this - downward spiral will continue to hold the congestion window below - path capacity until the connection is able to recover completely by - additive increase without experiencing loss. - - Of course, no downward spiral occurs if the error rate is constantly - high and the congestion window always remains small; the - multiplicative-increase "slow start" will be exited early, and the - congestion window remains low for the duration of the TCP connection. - In links with high error rates, the TCP window may remain rather - small for long periods of time. - - Not all causes of small windows are related to errors. For example, - HTTP/1.0 commonly closes TCP connections to indicate boundaries - between requested resources. This means that these applications are - constantly closing "trained" TCP connections and opening "untrained" - TCP connections which will execute slow start, beginning with one or - two segments. This can happen even with HTTP/1.1, if webmasters - configure their HTTP/1.1 servers to close connections instead of - waiting to see if the connection will be useful again. - - A small window - especially a window of less than four segments - - effectively prevents the sender from taking advantage of Fast - Retransmits. Moreover, efficient recovery from multiple losses - within a single window requires adoption of new proposals (NewReno - [RFC2582]). - - Recommendation: Implement Fast Retransmit and Fast Recovery at this - time. This is a widely-implemented optimization and is currently at - Proposed Standard level. [RFC2488] recommends implementation of Fast - Retransmit/Fast Recovery in satellite environments. - -2.3 Selective Acknowledgements [RFC2018, RFC2883] - - Selective Acknowledgements [RFC2018] allow the repair of multiple - segment losses per window without requiring one (or more) round-trips - per loss. - - - - - -Dawkins, et al. Best Current Practice [Page 7] - -RFC 3155 PILC - Links with Errors August 2001 - - - [RFC2883] proposes a minor extension to SACK that allows receiving - TCPs to provide more information about the order of delivery of - segments, allowing "more robust operation in an environment of - reordered packets, ACK loss, packet replication, and/or early - retransmit timeouts". Unless explicitly stated otherwise, in this - document, "Selective Acknowledgements" (or "SACK") refers to the - combination of [RFC2018] and [RFC2883]. - - Selective acknowledgments are most useful in LFNs ("Long Fat - Networks") because of the long round trip times that may be - encountered in these environments, according to Section 1.1 of - [RFC1323], and are especially useful if large windows are required, - because there is a higher probability of multiple segment losses per - window. - - On the other hand, if error rates are generally low but occasionally - higher due to channel conditions, TCP will have the opportunity to - increase its window to larger values during periods of improved - channel conditions between bursts of errors. When bursts of errors - occur, multiple losses within a window are likely to occur. In this - case, SACK would provide benefits in speeding the recovery and - preventing unnecessary reduction of the window size. - - Recommendation: Implement SACK as specified in [RFC2018] and updated - by [RFC2883], both Proposed Standards. In cases where SACK cannot be - enabled for both sides of a connection, TCP senders may use NewReno - [RFC2582] to better handle partial ACKs and multiple losses within a - single window. - -3.0 Summary of Recommendations - - The Internet does not provide a widely-available loss feedback - mechanism that allows TCP to distinguish between congestion loss and - transmission error. Because congestion affects all traffic on a path - while transmission loss affects only the specific traffic - encountering uncorrected errors, avoiding congestion has to take - precedence over quickly repairing transmission errors. This means - that the best that can be achieved without new feedback mechanisms is - minimizing the amount of time that is spent unnecessarily in - congestion avoidance. - - The Fast Retransmit/Fast Recovery mechanism allows quick repair of - loss without giving up the safety of congestion avoidance. In order - for Fast Retransmit/Fast Recovery to work, the window size must be - large enough to force the receiver to send three duplicate - acknowledgments before the retransmission timeout interval expires, - forcing full TCP slow-start. - - - - -Dawkins, et al. Best Current Practice [Page 8] - -RFC 3155 PILC - Links with Errors August 2001 - - - Selective Acknowledgements (SACK) extend the benefit of Fast - Retransmit/Fast Recovery to situations where multiple segment losses - in the window need to be repaired more quickly than can be - accomplished by executing Fast Retransmit for each segment loss, only - to discover the next segment loss. - - These mechanisms are not limited to wireless environments. They are - usable in all environments. - -4.0 Topics For Further Work - - "Limited Transmit" [RFC3042] has been specified as an optimization - extending Fast Retransmit/Fast Recovery for TCP connections with - small congestion windows that will not trigger three duplicate - acknowledgments. This specification is deemed safe, and it also - provides benefits for TCP connections that experience a large amount - of packet (data or ACK) loss. Implementors should evaluate this - standards track specification for TCP in loss environments. - - Delayed Duplicate Acknowledgements [MV97, VMPM99] attempts to prevent - TCP-level retransmission when link-level retransmission is still in - progress, adding additional traffic to the network. This proposal is - worthy of additional study, but is not recommended at this time, - because we don't know how to calculate appropriate amounts of delay - for an arbitrary network topology. - - It is not possible to use explicit congestion notification [RFC2481] - as a surrogate for explicit transmission error notification (no - matter how much we wish it was!). Some mechanism to provide explicit - notification of transmission error would be very helpful. This might - be more easily provided in a PEP environment, especially when the PEP - is the "first hop" in a connection path, because current checksum - mechanisms do not distinguish between transmission error to a payload - and transmission error to the header. Furthermore, if the header is - damaged, sending explicit transmission error notification to the - right endpoint is problematic. - - Losses that take place on the ACK stream, especially while a TCP is - learning network characteristics, can make the data stream quite - bursty (resulting in losses on the data stream, as well). Several - ways of limiting this burstiness have been proposed, including TCP - transmit pacing at the sender and ACK rate control within the - network. - - "Appropriate Byte Counting" (ABC) [ALL99], has been proposed as a way - of opening the congestion window based on the number of bytes that - have been successfully transfered to the receiver, giving more - appropriate behavior for application protocols that initiate - - - -Dawkins, et al. Best Current Practice [Page 9] - -RFC 3155 PILC - Links with Errors August 2001 - - - connections with relatively short packets. For SMTP [RFC2821], for - instance, the client might send a short HELO packet, a short MAIL - packet, one or more short RCPT packets, and a short DATA packet - - followed by the entire mail body sent as maximum-length packets. An - ABC TCP sender would not use ACKs for each of these short packets to - increase the congestion window to allow additional full-length - packets. ABC is worthy of additional study, but is not recommended - at this time, because ABC can lead to increased burstiness when - acknowledgments are lost. - -4.1 Achieving, and maintaining, large windows - - The recommendations described in this document will aid TCPs in - injecting packets into ERRORed connections as fast as possible - without destabilizing the Internet, and so optimizing the use of - available bandwidth. - - In addition to these TCP-level recommendations, there is still - additional work to do at the application level, especially with the - dominant application protocol on the World Wide Web, HTTP. - - HTTP/1.0 (and earlier versions) closes TCP connections to signal a - receiver that all of a requested resource had been transmitted. - Because WWW objects tend to be small in size [MOGUL], TCPs carrying - HTTP/1.0 traffic experience difficulty in "training" on available - path capacity (a substantial portion of the transfer has already - happened by the time TCP exits slow start). - - Several HTTP modifications have been introduced to improve this - interaction with TCP ("persistent connections" in HTTP/1.0, with - improvements in HTTP/1.1 [RFC2616]). For a variety of reasons, many - HTTP interactions are still HTTP/1.0-style - relatively short-lived. - - Proposals which reuse TCP congestion information across connections, - like TCP Control Block Interdependence [RFC2140], or the more recent - Congestion Manager [BS00] proposal, will have the effect of making - multiple parallel connections impact the network as if they were a - single connection, "trained" after a single startup transient. These - proposals are critical to the long-term stability of the Internet, - because today's users always have the choice of clicking on the - "reload" button in their browsers and cutting off TCP's exponential - backoff - replacing connections which are building knowledge of the - available bandwidth with connections with no knowledge at all. - - - - - - - - -Dawkins, et al. Best Current Practice [Page 10] - -RFC 3155 PILC - Links with Errors August 2001 - - -5.0 Security Considerations - - A potential vulnerability introduced by Fast Retransmit/Fast Recovery - is (as pointed out in [RFC2581]) that an attacker may force TCP - connections to grind to a halt, or, more dangerously, behave more - aggressively. The latter possibility may lead to congestion - collapse, at least in some regions of the network. - - Selective acknowledgments is believed to neither strengthen nor - weaken TCP's current security properties [RFC2018]. - - Given that the recommendations in this document are performed on an - end-to-end basis, they continue working even in the presence of end- - to-end IPsec. This is in direct contrast with mechanisms such as - PEP's which are implemented in intermediate nodes (section 1.2). - -6.0 IANA Considerations - - This document is a pointer to other, existing IETF standards. There - are no new IANA considerations. - -7.0 Acknowledgements - - This recommendation has grown out of RFC 2757, "Long Thin Networks", - which was in turn based on work done in the IETF TCPSAT working - group. The authors are indebted to the active members of the PILC - working group. In particular, Mark Allman and Lloyd Wood gave us - copious and insightful feedback, and Dan Grossman and Jamshid Mahdavi - provided text replacements. - -References - - [ALL99] M. Allman, "TCP Byte Counting Refinements," ACM Computer - Communication Review, Volume 29, Number 3, July 1999. - http://www.acm.org/sigcomm/ccr/archive/ccr-toc/ccr-toc- - 99.html - - [BS00] Balakrishnan, H. and S. Seshan, "The Congestion Manager", - RFC 3124, June 2001. - - [BV97] S. Biaz and N. Vaidya, "Using End-to-end Statistics to - Distinguish Congestion and Corruption Losses: A Negative - Result," Texas A&M University, Technical Report 97-009, - August 18, 1997. - - - - - - - -Dawkins, et al. Best Current Practice [Page 11] - -RFC 3155 PILC - Links with Errors August 2001 - - - [BV98] S. Biaz and N. Vaidya, "Sender-Based heuristics for - Distinguishing Congestion Losses from Wireless - Transmission Losses," Texas A&M University, Technical - Report 98-013, June 1998. - - [BV98a] S. Biaz and N. Vaidya, "Discriminating Congestion Losses - from Wireless Losses using Inter-Arrival Times at the - Receiver," Texas A&M University, Technical Report 98-014, - June 1998. - - [MOGUL] "The Case for Persistent-Connection HTTP", J. C. Mogul, - Research Report 95/4, May 1995. Available as - http://www.research.digital.com/wrl/techreports/abstracts/ - 95.4.html - - [MV97] M. Mehta and N. Vaidya, "Delayed Duplicate- - Acknowledgements: A Proposal to Improve Performance of - TCP on Wireless Links," Texas A&M University, December 24, - 1997. Available at - http://www.cs.tamu.edu/faculty/vaidya/mobile.html - - [PILC-WEB] http://pilc.grc.nasa.gov/ - - [PFTK98] Padhye, J., Firoiu, V., Towsley, D. and J.Kurose, "TCP - Throughput: A simple model and its empirical validation", - SIGCOMM Symposium on Communications Architectures and - Protocols, August 1998. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC2821] Klensin, J., Editor, "Simple Mail Transfer Protocol", RFC - 2821, April 2001. - - [RFC1122] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC1191] Mogul J., and S. Deering, "Path MTU Discovery", RFC 1191, - November 1990. - - [RFC1323] Jacobson, V., Braden, R. and D. Borman. "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow "TCP - Selective Acknowledgment Options", RFC 2018, October 1996. - - [RFC2140] Touch, J., "TCP Control Block Interdependence", RFC 2140, - April 1997. - - - -Dawkins, et al. Best Current Practice [Page 12] - -RFC 3155 PILC - Links with Errors August 2001 - - - [RFC2309] Braden, B., Clark, D., Crowcrfot, J., Davie, B., Deering, - S., Estrin, D., Floyd, S., Jacobson, V., Minshall, G., - Partridge, C., Peterson, L., Ramakrishnan, K., Shecker, - S., Wroclawski, J. and L, Zhang, "Recommendations on Queue - Management and Congestion Avoidance in the Internet", RFC - 2309, April 1998. - - [RFC2481] Ramakrishnan K. and S. Floyd, "A Proposal to add Explicit - Congestion Notification (ECN) to IP", RFC 2481, January - 1999. - - [RFC2488] Allman, M., Glover, D. and L. Sanchez. "Enhancing TCP Over - Satellite Channels using Standard Mechanisms", BCP 28, RFC - 2488, January 1999. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2582] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., - Masinter, L., Leach P. and T. Berners-Lee, "Hypertext - Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. - - [RFC2861] Handley, H., Padhye, J. and S., Floyd, "TCP Congestion - Window Validation", RFC 2861, June 2000. - - [RFC2883] Floyd, S., Mahdavi, M., Mathis, M. and M. Podlosky, "An - Extension to the Selective Acknowledgement (SACK) Option - for TCP", RFC 2883, August 1999. - - [RFC2923] Lahey, K., "TCP Problems with Path MTU Discovery", RFC - 2923, September 2000. - - [RFC3042] Allman, M., Balakrishnan, H. and S. Floyd, "Enhancing - TCP's Loss Recovery Using Limited Transmit", RFC 3042, - January, 2001. - - [RFC3135] Border, J., Kojo, M., Griner, J., Montenegro, G. and Z. - Shelby, "Performance Enhancing Proxies Intended to - Mitigate Link-Related Degradations", RFC 3135, June 2001. - - [VJ-DCAC] Jacobson, V., "Dynamic Congestion Avoidance / Control" e- - mail dated February 11, 1988, available from - http://www.kohala.com/~rstevens/vanj.88feb11.txt - - - - - -Dawkins, et al. Best Current Practice [Page 13] - -RFC 3155 PILC - Links with Errors August 2001 - - - [VMPM99] N. Vaidya, M. Mehta, C. Perkins, and G. Montenegro, - "Delayed Duplicate Acknowledgements: A TCP-Unaware - Approach to Improve Performance of TCP over Wireless," - Technical Report 99-003, Computer Science Dept., Texas A&M - University, February 1999. Also, to appear in Journal of - Wireless Communications and Wireless Computing (Special - Issue on Reliable Transport Protocols for Mobile - Computing). - -Authors' Addresses - - Questions about this document may be directed to: - - Spencer Dawkins - Fujitsu Network Communications - 2801 Telecom Parkway - Richardson, Texas 75082 - - Phone: +1-972-479-3782 - EMail: spencer.dawkins@fnc.fujitsu.com - - - Gabriel E. Montenegro - Sun Microsystems - Laboratories, Europe - 29, chemin du Vieux Chene - 38240 Meylan - FRANCE - - Phone: +33 476 18 80 45 - EMail: gab@sun.com - - - Markku Kojo - Department of Computer Science - University of Helsinki - P.O. Box 26 (Teollisuuskatu 23) - FIN-00014 HELSINKI - Finland - - Phone: +358-9-1914-4179 - EMail: kojo@cs.helsinki.fi - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 14] - -RFC 3155 PILC - Links with Errors August 2001 - - - Vincent Magret - Alcatel Internetworking, Inc. - 26801 W. Agoura road - Calabasas, CA, 91301 - - Phone: +1 818 878 4485 - EMail: vincent.magret@alcatel.com - - - Nitin H. Vaidya - 458 Coodinated Science Laboratory, MC-228 - 1308 West Main Street - Urbana, IL 61801 - - Phone: 217-265-5414 - E-mail: nhv@crhc.uiuc.edu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 15] - -RFC 3155 PILC - Links with Errors August 2001 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Dawkins, et al. Best Current Practice [Page 16] - diff --git a/ext/picotcp/RFC/rfc3360.txt b/ext/picotcp/RFC/rfc3360.txt deleted file mode 100644 index af27470..0000000 --- a/ext/picotcp/RFC/rfc3360.txt +++ /dev/null @@ -1,1067 +0,0 @@ - - - - - - -Network Working Group S. Floyd -Request for Comments: 3360 ICIR -BCP: 60 August 2002 -Category: Best Current Practice - - - Inappropriate TCP Resets Considered Harmful - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document is being written because there are a number of - firewalls in the Internet that inappropriately reset a TCP connection - upon receiving certain TCP SYN packets, in particular, packets with - flags set in the Reserved field of the TCP header. In this document - we argue that this practice is not conformant with TCP standards, and - is an inappropriate overloading of the semantics of the TCP reset. - We also consider the longer-term consequences of this and similar - actions as obstacles to the evolution of the Internet infrastructure. - -1. Introduction - - TCP uses the RST (Reset) bit in the TCP header to reset a TCP - connection. Resets are appropriately sent in response to a - connection request to a nonexistent connection, for example. The TCP - receiver of the reset aborts the TCP connection, and notifies the - application [RFC793, RFC1122, Ste94]. - - Unfortunately, a number of firewalls and load-balancers in the - current Internet send a reset in response to a TCP SYN packet that - use flags from the Reserved field in the TCP header. Section 3 below - discusses the specific example of firewalls that send resets in - response to TCP SYN packets from ECN-capable hosts. - - This document is being written to inform administrators of web - servers and firewalls of this problem, in an effort to encourage the - deployment of bug-fixes [FIXES]. A second purpose of this document - is to consider the longer-term consequences of such middlebox - behavior on the more general evolution of protocols in the Internet. - - - -Floyd Best Current Practice [Page 1] - -RFC 3360 Inappropriate TCP Resets August 2002 - - -2. The history of TCP resets. - - This section gives a brief history of the use of the TCP reset in the - TCP standards, and argues that sending a reset in response to a SYN - packet that uses bits from the Reserved field of the TCP header is - non-compliant behavior. - - RFC 793 contained the original specification of TCP in September, - 1981 [RFC793]. This document defined the RST bit in the TCP header, - and explained that reset was devised to prevent old duplicate - connection initiations from causing confusion in TCP's three-way - handshake. The reset is also used when a host receives data for a - TCP connection that no longer exists. - - RFC 793 states the following, in Section 5: - - "As a general rule, reset (RST) must be sent whenever a segment - arrives which apparently is not intended for the current connection. - A reset must not be sent if it is not clear that this is the case." - - RFC 1122 "amends, corrects, and supplements" RFC 793. RFC 1122 says - nothing specific about sending resets, or not sending resets, in - response to flags in the TCP Reserved field. - - Thus, there is nothing in RFC 793 or RFC 1122 that suggests that it - is acceptable to send a reset simply because a SYN packet uses - Reserved flags in the TCP header, and RFC 793 explicitly forbids - sending a reset for this reason. - - RFC 793 and RFC 1122 both include Jon Postel's famous robustness - principle, also from RFC 791: "Be liberal in what you accept, and - conservative in what you send." RFC 1122 reiterates that this - robustness principle "is particularly important in the Internet - layer, where one misbehaving host can deny Internet service to many - other hosts." The discussion of the robustness principle in RFC 1122 - also states that "adaptability to change must be designed into all - levels of Internet host software". The principle "be liberal in what - you accept" doesn't carry over in a clear way (if at all) to the - world of firewalls, but the issue of "adaptability to change" is - crucial nevertheless. The challenge is to protect legitimate - security interests without completely blocking the ability of the - Internet to evolve to support new applications, protocols, and - functionality. - - - - - - - - -Floyd Best Current Practice [Page 2] - -RFC 3360 Inappropriate TCP Resets August 2002 - - -2.1. The TCP Reserved Field - - RFC 793 says that the Reserved field in the TCP header is reserved - for future use, and must be zero. A rephrasing more consistent with - the rest of the document would have been to say that the Reserved - field should be zero when sent and ignored when received, unless - specified otherwise by future standards actions. However, the - phrasing in RFC 793 does not permit sending resets in response to TCP - packets with a non-zero Reserved field, as is explained in the - section above. - -2.2. Behavior of and Requirements for Internet Firewalls - - RFC 2979 on the Behavior of and Requirements for Internet Firewalls - [RFC2979], an Informational RFC, contains the following: - - "Applications have to continue to work properly in the presence of - firewalls. This translates into the following transparency rule: The - introduction of a firewall and any associated tunneling or access - negotiation facilities MUST NOT cause unintended failures of - legitimate and standards-compliant usage that would work were the - firewall not present." - - "A necessary corollary to this requirement is that when such failures - do occur it is incumbent on the firewall and associated software to - address the problem: Changes to either implementations of existing - standard protocols or the protocols themselves MUST NOT be - necessary." - - "Note that this requirement only applies to legitimate protocol usage - and gratuitous failures -- a firewall is entitled to block any sort - of access that a site deems illegitimate, regardless of whether or - not the attempted access is standards-compliant." - - We would note that RFC 2979 is an Informational RFC. RFC 2026 on - Internet Standards Process says the following in Section 4.2.2: "An - `Informational' specification is published for the general - information of the Internet community, and does not represent an - Internet community consensus or recommendation" [RFC2026]. - -2.3. Sending Resets as a Congestion Control Mechanism - - Some firewalls and hosts send resets in response to SYN packets as a - congestion control mechanism, for example, when their listen queues - are full. These resets are sent without regard to the contents of - the TCP Reserved field. Possibly in response to the use of resets as - - - - - -Floyd Best Current Practice [Page 3] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - a congestion control mechanism, several popular TCP implementations - immediately resend a SYN packet in response to a reset, up to four - times. - - We would recommend that the TCP reset not be used as a congestion - control mechanism, because this overloads the semantics of the reset - message, and inevitably leads to more aggressive behavior from TCP - implementations in response to a reset. We would suggest that simply - dropping the SYN packet is the most effective response to congestion. - The TCP sender will retransmit the SYN packet, using the default - value for the Retransmission Timeout (RTO), backing-off the - retransmit timer after each retransmit. - -2.4. Resets in Response to Changes in the Precedence Field - - RFC 793 includes the following in Section 5: - - "If an incoming segment has a security level, or compartment, or - precedence which does not exactly match the level, and compartment, - and precedence requested for the connection, a reset is sent and - connection goes to the CLOSED state." - - The "precedence" refers to the (old) Precedence field in the (old) - ToS field in the IP header. The "security" and "compartment" refer - to the obsolete IP Security option. When it was written, this was - consistent with the guideline elsewhere in RFC 793 that resets should - only be sent when a segment arrives which apparently is not intended - for the current connection. - - RFC 2873 on "TCP Processing of the IPv4 Precedence Field" discusses - specific problems raised by the sending of resets when the precedence - field has changed [RFC2873]. RFC 2873, currently a Proposed - Standard, specifies that TCP must ignore the precedence of all - received segments, and must not send a reset in response to changes - in the precedence field. We discuss this here to clarify that this - issue never permitted the sending of a reset in response to a segment - with a non-zero TCP Reserved field. - -2.5. Resets in Response to Illegal Option Lengths - - RFC 1122 says the following in Section 4.2.2.5 about TCP options - [RFC1122]: - - "A TCP MUST be able to receive a TCP option in any segment. A TCP - MUST ignore without error any TCP option it does not implement, - assuming that the option has a length field (all TCP options defined - - - - - -Floyd Best Current Practice [Page 4] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - in the future will have length fields). TCP MUST be prepared to - handle an illegal option length (e.g., zero) without crashing; a - suggested procedure is to reset the connection and log the reason." - - This makes sense, as a TCP receiver is unable to interpret the rest - of the data on a segment that has a TCP option with an illegal option - length. Again, we discuss this here to clarify that this issue never - permitted the sending of a reset in response to a segment with a - non-zero TCP Reserved field. - -3. The Specific Example of ECN - - This section has a brief explanation of ECN (Explicit Congestion - Notification) in general, and the ECN-setup SYN packet in particular. - - The Internet is based on end-to-end congestion control, and - historically the Internet has used packet drops as the only method - for routers to indicate congestion to the end nodes. ECN is a recent - addition to the IP architecture to allow routers to set a bit in the - IP packet header to inform end-nodes of congestion, instead of - dropping the packet. ECN requires the cooperation of the transport - end-nodes. - - The ECN specification, RFC 2481, was an Experimental RFC from January - 1999 until June 2001, when a revised document [RFC3168] was approved - as Proposed Standard. More information about ECN is available from - the ECN Web Page [ECN]. - - The use of ECN with TCP requires that both TCP end-nodes have been - upgraded to support the use of ECN, and that both end-nodes agree to - use ECN with this particular TCP connection. This negotiation of ECN - support between the two TCP end-nodes uses two flags that have been - allocated from the Reserved field in the TCP header [RFC2481]. - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - | | | U | A | P | R | S | F | - | Header Length | Reserved | R | C | S | S | Y | I | - | | | G | K | H | T | N | N | - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - - Figure 1: The previous definition of bytes 13 and 14 of the TCP - header. - - - - - - - - -Floyd Best Current Practice [Page 5] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - | | | C | E | U | A | P | R | S | F | - | Header Length | Reserved | W | C | R | C | S | S | Y | I | - | | | R | E | G | K | H | T | N | N | - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - - Figure 2: The current definition of bytes 13 and 14 of the TCP - Header, from RFC 3168. - - The two ECN flags in the TCP header are defined from the last two - bits in the Reserved field of the TCP header. Bit 9 in the Reserved - field of the TCP header is designated as the ECN-Echo flag (ECE), and - Bit 8 is designated as the Congestion Window Reduced (CWR) flag. To - negotiate ECN usage, the TCP sender sends an "ECN-setup SYN packet", - a TCP SYN packet with the ECE and CWR flags set. If the TCP host at - the other end wishes to use ECN for this connection, then it sends an - "ECN-setup SYN-ACK packet", a TCP SYN packet with the ECE flag set - and the CWR flag not set. Otherwise, the TCP host at the other end - returns a SYN-ACK packet with neither the ECE nor the CWR flag set. - - So now back to TCP resets. When a TCP host negotiating ECN sends an - ECN-setup SYN packet, an old TCP implementation is expected to ignore - those flags in the Reserved field, and to send a plain SYN-ACK packet - in response. However, there are some broken firewalls and load- - balancers in the Internet that instead respond to an ECN-setup SYN - packet with a reset. Following the deployment of ECN-enabled end - nodes, there were widespread complaints that ECN-capable hosts could - not access a number of websites [Kelson00]. This has been - investigated by the Linux community, and by the TBIT project [TBIT] - in data taken from September, 2000, up to March, 2002, and has been - discussed in an article in Enterprise Linux Today [Cou01]. Some of - the offending equipment has been identified, and a web page [FIXES] - contains a list of non-compliant products and the fixes posted by the - vendors. In March 2002, six months after ECN was approved as - Proposed Standard, ECN-setup SYN packets were answered by a reset - from 203 of the 12,364 web sites tested, and ECN-setup SYN packets - were dropped for 420 of the web sites. Installing software that - blocks packets using flags in TCP's Reserved field is considerably - easier than uninstalling that software later on. - -3.1. ECN: The Work-Around. - - A work-around for maintaining connectivity in the face of the broken - equipment was described in [Floyd00], and has been specified in RFC - 3168 as a procedure that may be included in TCP implementations. We - describe this work-around briefly below. - - - - -Floyd Best Current Practice [Page 6] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - To provide robust connectivity even in the presence of faulty - equipment, a TCP host that receives a reset in response to the - transmission of an ECN-setup SYN packet may resend the SYN with CWR - and ECE cleared. This would result in a TCP connection being - established without using ECN. This also has the unfortunate result - of the ECN-capable TCP host not responding properly to the first - valid reset. If a second reset is sent in response to the second - SYN, which had CWR and ECE cleared, then the TCP host should respond - properly by aborting the connection. - - Similarly, a host that receives no reply to an ECN-setup SYN within - the normal SYN retransmission timeout interval may resend the SYN and - any subsequent SYN retransmissions with CWR and ECE cleared. To - overcome normal packet loss that results in the original SYN being - lost, the originating host may retransmit one or more ECN-setup SYN - packets before giving up and retransmitting the SYN with the CWR and - ECE bits cleared. - - Some TCP implementors have so far decided not to deploy these - workarounds, for the following reasons: - - * The work-arounds would result in ECN-capable hosts not responding - properly to the first valid reset received in response to a SYN - packet. - - * The work-arounds would limit ECN functionality in environments - without broken equipment, by disabling ECN where the first SYN or - SYN-ACK packet was dropped in the network. - - * The work-arounds in many cases would involve a delay of six seconds - or more before connectivity is established with the remote server, - in the case of broken equipment that drops ECN-setup SYN packets. - By accommodating this broken equipment, the work-arounds have been - judged as implicitly accepting both this delay and the broken - equipment that would be causing this delay. - - One possibility would be for such work-arounds to be configurable by - the user. - - One unavoidable consequence of the work-around of resending a - modified SYN packet in response to a reset is to further erode the - semantics of the TCP reset. Thus, when a box sends a reset, the TCP - host receiving that reset does not know if the reset was sent simply - because of the ECN-related flags in the TCP header, or because of - some more fundamental problem. Therefore, the TCP host resends the - TCP SYN packet without the ECN-related flags in the TCP header. The - ultimate consequence of this absence of clear communications from the - middlebox to the end-nodes could be an extended spiral of - - - -Floyd Best Current Practice [Page 7] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - communications specified for transport protocols, as end nodes - attempt to sacrifice as little functionality as possible in the - process of determining which packets will and will not be forwarded - to the other end. This is discussed in more detail in Section 6.1 - below. - -4. On Combating Obstacles to the Proper Evolution of the Internet - Infrastructure - - One of the reasons that this issue of inappropriate resets is - important (to me) is that it has complicated the deployment of ECN in - the Internet (though it has fortunately not blocked the deployment - completely). It has also added an unnecessary obstacle to the future - effectiveness of ECN. - - However, a second, more general reason why this issue is important is - that the presence of equipment in the Internet that rejects valid TCP - packets limits the future evolution of TCP, completely aside from the - issue of ECN. That is, the widespread deployment of equipment that - rejects TCP packets that use Reserved flags in the TCP header could - effectively prevent the deployment of new mechanisms that use any of - these Reserved flags. It doesn't matter if these new mechanisms have - the protection of Experimental or Proposed Standard status from the - IETF, because the broken equipment in the Internet does not stop to - look up the current status of the protocols before rejecting the - packets. TCP is good, and useful, but it would be a pity for the - deployment of broken equipment in the Internet to result in the - "freezing" of TCP in its current state, without the ability to use - the Reserved flags in the future evolution of TCP. - - In the specific case of middleboxes that block TCP SYN packets - attempting to negotiate ECN, the work-around described in Section 3.1 - is sufficient to ensure that end-nodes could still establish - connectivity. However, there are likely to be additional uses of the - TCP Reserved Field standardized in the next year or two, and these - additional uses might not coexist quite as successfully with - middleboxes that send resets. Consider the difficulties that could - result if a path changes in the middle of a connection's lifetime, - and the middleboxes on the old and new paths have different policies - about exactly which flags in the TCP Reserved field they would and - would not block. - - Taking the wider view, the existence of web servers or firewalls that - send inappropriate resets is only one example of functionality in the - Internet that restricts the future evolution of the Internet. The - impact of all of these small restrictions taken together presents a - considerable obstacle to the development of the Internet - architecture. - - - -Floyd Best Current Practice [Page 8] - -RFC 3360 Inappropriate TCP Resets August 2002 - - -5. Issues for Transport Protocols - - One lesson for designers of transport protocols is that transport - protocols will have to protect themselves from the unknown and - seemingly arbitrary actions of firewalls, normalizers, and other - middleboxes in the network. For the moment, for TCP, this means - sending a non-ECN-setup SYN when a reset is received in response to - an ECN-setup SYN packet. Defensive actions on the side of transport - protocols could include using Reserved flags in the SYN packet before - using them in data traffic, to protect against middleboxes that block - packets using those flags. It is possible that transport protocols - will also have to add additional checks during the course of the - connection lifetime to check for interference from middleboxes along - the path. - - The ECN standards document, RFC 3168, contains an extensive - discussion in Section 18 on "Possible Changes to the ECN Field in the - Network", but includes the following about possible changes to the - TCP header: - - "This document does not consider potential dangers introduced by - changes in the transport header within the network. We note that - when IPsec is used, the transport header is protected both in tunnel - and transport modes [ESP, AH]." - - With the current modification of transport-level headers in the - network by firewalls (as discussed below in Section 6.2), future - protocol designers might no longer have the luxury of ignoring the - possible impact of changes to the transport header within the - network. - - Transport protocols will also have to respond in some fashion to an - ICMP code of "Communication Administratively Prohibited" if - middleboxes start to use this form of the ICMP Destination - Unreachable message to indicate that the packet is using - functionality not allowed [RFC1812]. - -6. Issues for Middleboxes - - Given that some middleboxes are going to drop some packets because - they use functionality not allowed by the middlebox, the larger issue - remains of how middleboxes should communicate the reason for this - action to the end-nodes, if at all. One suggestion, for - consideration in more depth in a separate document, would be that - firewalls send an ICMP Destination Unreachable message with the code - "Communication Administratively Prohibited" [B01]. - - - - - -Floyd Best Current Practice [Page 9] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - We acknowledge that this is not an ideal solution, for several - reasons. First, middleboxes along the reverse path might block these - ICMP messages. Second, some firewall operators object to explicit - communication because it reveals too much information about security - policies. And third, the response of transport protocols to such an - ICMP message is not yet specified. - - However, an ICMP "Administratively Prohibited" message could be a - reasonable addition, for firewalls willing to use explicit - communication. One possibility, again to be explored in a separate - document, would be for the ICMP "Administratively Prohibited" message - to be modified to convey additional information to the end host. - - We would note that this document does not consider middleboxes that - block complete transport protocols. We also note that this document - is not addressing firewalls that send resets in response to a TCP SYN - packet to a firewalled-off TCP port. Such a use of resets seems - consistent with the semantics of TCP reset. This document is only - considering the problems caused by middleboxes that block specific - packets within a transport protocol when other packets from that - transport protocol are forwarded by the middlebox unaltered. - - One complication is that once a mechanism is installed in a firewall - to block a particular functionality, it can take considerable effort - for network administrators to "un-install" that block. It has been - suggested that tweakable settings on firewalls could make recovery - from future incidents less painful all around. Again, because this - document does not address more general issues about firewalls, the - issue of greater firewall flexibility, and the attendant possible - security risks, belongs in a separate document. - -6.1. Current Choices for Firewalls - - Given a firewall that has decided to drop TCP packets that use - reserved bits in the TCP header, one question is whether the firewall - should also send a Reset, in order to prevent the TCP connection from - consuming unnecessary resources at the TCP sender waiting for the - retransmit timeout. We would argue that whether or not the firewall - feels compelled to drop the TCP packet, it is not appropriate to send - a TCP reset. Sending a TCP reset in response to prohibited - functionality would continue the current overloading of the semantics - of the TCP reset in a way that could be counterproductive all around. - - As an example, Section 2.3 has already observed that some firewalls - send resets in response to TCP SYN packets as a congestion control - mechanism. Possibly in response to this (or perhaps in response to - something else), some popular TCP implementations immediately resend - a SYN packet in response to a reset, up to four times. Other TCP - - - -Floyd Best Current Practice [Page 10] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - implementations, in conformance to the standards, don't resend SYN - packets after receiving a reset. The more aggressive TCP - implementations increase congestion for others, but also increase - their own chances of eventually getting through. Giving these fluid - semantics for the TCP reset, one might expect more TCP - implementations to start resending SYN packets in response to a - reset, completely apart from any issues having to do with ECN. - Obviously, this weakens the effectiveness of the reset when used for - its original purpose, of responding to TCP packets that apparently - are not intended for the current connection. - - If we add to this mix the use of the TCP reset by firewalls in - response to TCP packets using reserved bits in the TCP header, this - muddies the waters further. Because TCP resets could be sent due to - congestion, or to prohibited functionality, or because a packet was - received from a previous TCP connection, TCP implementations (or, - more properly, TCP implementors) would now have an incentive to be - even more persistent in resending SYN packets in response to TCP - resets. In addition to the incentive mentioned above of resending - TCP SYN packets to increase one's odds of eventually getting through - in a time of congestion, the TCP reset might have been due to - prohibited functionality instead of congestion, so the TCP - implementation might resend SYN packets in different forms to - determine exactly which functionality is being prohibited. Such a - continual changing of the semantics of the TCP reset could be - expected to lead to a continued escalation of measures and - countermeasures between firewalls and end-hosts, with little - productive benefit to either side. - - It could be argued that *dropping* the TCP SYN packet due to the use - of prohibited functionality leads to overloading of the semantics of - a packet drop, in the same way that the reset leads to overloading - the semantics of a reset. This is true; from the viewpoint of end- - system response to messages with overloaded semantics, it would be - preferable to have an explicit indication about prohibited - functionality (for those firewalls for some reason willing to use - explicit indications). But given a firewall's choice between sending - a reset or just dropping the packet, we would argue that just - dropping the packet does less damage, in terms of giving an incentive - to end-hosts to adopt counter-measures. It is true that just - dropping the packet, without sending a reset, results in delay for - the TCP connection in resending the SYN packet without the prohibited - functionality. However, sending a reset has the undesirable longer- - term effect of giving an incentive to future TCP implementations to - add more baroque combinations of resending SYN packets in response to - a reset, because the TCP sender can't tell if the reset is for a - standard reason, for congestion, or for the prohibited functionality - of option X or reserved bit Y in the TCP header. - - - -Floyd Best Current Practice [Page 11] - -RFC 3360 Inappropriate TCP Resets August 2002 - - -6.2. The Complications of Modifying Packet Headers in the Network - - In addition to firewalls that send resets in response to ECN-setup - SYN packets and firewalls that drop ECN-setup SYN packets, there also - exist firewalls that by default zero the flags in the TCP Reserved - field, including the two flags used for ECN. We note that in some - cases this could have unintended and undesirable consequences. - - If a firewall zeros the ECN-related flags in the TCP header in the - initial SYN packet, then the TCP connection will be set up without - using ECN, and the ECN-related flags in the TCP header will be sent - zeroed-out in all of the subsequent packets in this connection. This - will accomplish the firewall's purpose of blocking ECN, while - allowing the TCP connection to proceed efficiently and smoothly - without using ECN. - - If for some reason the ECN-related flags in the TCP header aren't - zeroed in the initial SYN packet from host A to host B, but the - firewall does zero those flags in the responding SYN/ACK packet from - host B to host A, the consequence could be to subvert end-to-end - congestion control for this connection. The ECN specifications were - not written to ensure robust operation in the presence of the - arbitrary zeroing of TCP header fields within the network, because it - didn't occur to the authors of the protocol at the time that this was - a requirement in protocol design. - - Similarly, if the ECN-related flags in the TCP header are not zeroed - in either the SYN or the SYN/ACK packet, but the firewall does zero - these flags in later packets in that TCP connection, this could also - have the unintended consequence of subverting end-to-end congestion - control for this connection. The details of these possible - interactions are not crucial for this document, and are described in - the appendix. However, our conclusion, both for the ECN-related - flags in the TCP header and for future uses of the four other bits in - the TCP Reserved field, would be that if it is required for firewalls - to be able to block the use of a new function being added to a - protocol, this is best addressed in the initial design phase by joint - cooperation between the firewall community and the protocol - designers. - -7. Conclusions - - Our conclusion is that it is not conformant with current standards - for a firewall, load-balancer, or web-server to respond with a reset - to a TCP SYN packet simply because the packet uses flags in the TCP - Reserved field. More specifically, it is not conformant to respond - with a reset to a TCP SYN packet simply because the ECE and CWR flags - are set in the IP header. We would urge vendors to make available - - - -Floyd Best Current Practice [Page 12] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - fixes for any nonconformant code, and we could urge ISPs and system - administrators to deploy these fixes in their web servers and - firewalls. - - We don't claim that it violates any standard for middleboxes to - arbitrarily drop packets that use flags in the TCP Reserved field, - but we would argue that behavior of this kind, without a clear method - for informing the end-nodes of the reasons for these actions, could - present a significant obstacle to the development of TCP. More work - is clearly needed to reconcile the conflicting interests of providing - security while at the same time allowing the careful evolution of - Internet protocols. - -8. Acknowledgements - - This document results from discussions and activity by many people, - so I will refrain from trying to acknowledge all of them here. My - specific thanks go to Ran Atkinson, Steve Bellovin, Alex Cannara, - Dennis Ferguson, Ned Freed, Mark Handley, John Klensin, Allison - Mankin, Jitendra Padhye, Vern Paxson, K. K. Ramakrishnan, Jamal Hadi - Salim, Pekka Savola, Alex Snoeren, and Dan Wing for feedback on this - document, and to the End-to-End Research Group, the IAB, and the IESG - for discussion of these issues. I thank Mikael Olsson for numerous - rounds of feedback. I also thank the members of the Firewall Wizards - mailing list for feedback (generally of disagreement) on an earlier - draft of this document. - - Email discussions with a number of people, including Dax Kelson, - Alexey Kuznetsov, Kacheong Poon, David Reed, Jamal Hadi-Salim, and - Venkat Venkatsubra, have addressed the issues raised by non- - conformant equipment in the Internet that does not respond to TCP SYN - packets with the ECE and CWR flags set. We thank Mark Handley, - Jitentra Padhye, and others for discussions on the TCP initialization - procedures. - -9. Normative References - - [RFC793] Postel, J., "Transmission Control Protocol - DARPA - Internet Program Protocol Specification", STD 7, RFC 793, - September 1981. - - [RFC1122] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC1812] Baker, F., "Requirements for IP Version 4 Routers", RFC - 1812, June 1995. - - - - - -Floyd Best Current Practice [Page 13] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - [RFC2026] Bradner, S., "The Internet Standards Process -- Revision - 3", BCP 9, RFC 2026, October 1996. - - [RFC2481] Ramakrishnan, K. and S. Floyd, "A Proposal to add Explicit - Congestion Notification (ECN) to IP", RFC 2481, January - 1999. - - [RFC2873] Xiao, X., Hannan, A., Paxson, V., and E. Crabbe, "TCP - Processing of the IPv4 Precedence Field, RFC 2873, June - 2000. - - [RFC2979] Freed, N., " Behavior of and Requirements for Internet - Firewalls", RFC 2979, October 2000. - - [RFC3168] Ramakrishnan, K., Floyd, S. and D. Black, "The Addition - of Explicit Congestion Notification (ECN) to IP", RFC - 3168, September 2001. - -10. Informative References - - [B01] Bellovin, S., "A "Reason" Field for ICMP "Administratively - Prohibited" Messages", Work in Progress. - - [Cou01] Scott Courtney, Why Can't My 2.4 Kernel See Some Web - Sites?, Enterprise Linux Today, Apr 17, 2001. URL - "http://eltoday.com/article.php3?ltsn=2001-04-17-001-14- - PS". - - [ECN] "The ECN Web Page", URL - "http://www.icir.org/floyd/ecn.html". - - [FIXES] ECN-under-Linux Unofficial Vendor Support Page, URL - "http://gtf.org/garzik/ecn/". - - [Floyd00] Sally Floyd, Negotiating ECN-Capability in a TCP - connection, October 2, 2000, email to the end2end-interest - mailing list. URL - "http://www.icir.org/floyd/papers/ECN.Oct2000.txt". - - [Kelson00] Dax Kelson, note sent to the Linux kernel mailing list, - September 10, 2000. - - [QUESO] Toby Miller, Intrusion Detection Level Analysis of Nmap - and Queso, August 30, 2000. URL - "http://www.securityfocus.com/infocus/1225". - - - - - - -Floyd Best Current Practice [Page 14] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - [Ste94] Stevens, W., "TCP/IP Illustrated, Volume 1: The - Protocols", Addison-Wesley, 1994. - - [SFO01] FreeBSD ipfw Filtering Evasion Vulnerability, Security - Focus Online, January 23, 2001. URL - "http://www.securityfocus.com/bid/2293". - - [TBIT] Jitendra Padhye and Sally Floyd, Identifying the TCP - Behavior of Web Servers, SIGCOMM, August 2001. URL - "http://www.icir.org/tbit/". - -11. Security Considerations - - One general risk of using Reserved flags in TCP is the risk of - providing additional information about the configuration of the host - in question. However, TCP is sufficiently loosely specified as it - is, with sufficiently many variants and options, that port-scanning - tools such as Nmap and Queso do rather well in identifying the - configuration of hosts even without the use of Reserved flags. - - The security considerations and all other considerations of a - possible ICMP Destination Unreachable message with the code - "Communication Administratively Prohibited" will be discussed in a - separate document. - - The traditional concern of firewalls is to prevent unauthorized - access to systems, to prevent DoS attacks and other attacks from - subverting the end-user terminal, and to protect end systems from - buggy code. We are aware of one security vulnerability reported from - the use of the Reserved flags in the TCP header [SFO01]. A packet - filter intended only to let through packets in established - connections can let pass a packet not in an established connection if - the packet has the ECE flag set in the reserved field. "Exploitation - of this vulnerability may allow for unauthorized remote access to - otherwise protected services." It is also possible that an - implementation of TCP could appear that has buggy code associated - with the use of Reserved flags in the TCP header, but we are not - aware of any such implementation at the moment. - - Unfortunately, misconceived security concerns are one of the reasons - for the problems described in this document in the first place. An - August, 2000, article on "Intrusion Detection Level Analysis of Nmap - and Queso" described the port-scanning tool Queso as sending SYN - packets with the last two Reserved bits in the TCP header set, and - said the following: "[QUESO] is easy to identify, if you see [these - two Reserved bits and the SYN bit] set in the 13th byte of the TCP - header, you know that someone has malicious intentions for your - network." As is documented on the TBIT Web Page, the middleboxes - - - -Floyd Best Current Practice [Page 15] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - that block SYNs using the two ECN-related Reserved flags in the TCP - header do not block SYNs using other Reserved flags in the TCP - header. - - One lesson appears to be that anyone can effectively "attack" a new - TCP function simply by using that function in their publicly- - available port-scanning tool, thus causing middleboxes of all kinds - to block the use of that function. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Floyd Best Current Practice [Page 16] - -RFC 3360 Inappropriate TCP Resets August 2002 - - -12. Appendix: The Complications of Modifying Packet Headers - - In this section we first show that if the ECN-related flags in the - TCP header aren't zeroed in the initial SYN packet from Host A to - Host B, but are zeroed in the responding SYN/ACK packet from Host B - to Host A, the consequence could be to subvert end-to-end congestion - control for this connection. - - Assume that the ECN-setup SYN packet from Host A is received by Host - B, but the ECN-setup SYN/ACK from Host B is modified by a firewall in - the network to a non-ECN-setup SYN/ACK, as in Figure 3 below. RFC - 3168 does not specify that the ACK packet in any way should echo the - TCP flags received in the SYN/ACK packet, because it had not occurred - to the designers that these flags would be modified within the - network. - - Host A Firewall or router Host B - ----------------------------------------------------------------- - Sends ECN-setup SYN ----------------> Receives ECN-setup SYN - <- Sends ECN-setup SYN/ACK - <- Firewall zeros flags - Receives non-ECN-setup SYN/ACK - Sends ACK and data ----------------> Receives ACK and data - <- Sends data packet with ECT - <- Router sets CE - Receives data packet with ECT and CE - - Figure 3: ECN-related flags in SYN/ACK packet cleared in network. - - Following RFC 3168, Host A has received a non-ECN-setup SYN/ACK - packet, and must not set ECT on data packets. Host B, however, does - not know that Host A has received a non-ECN-setup SYN/ACK packet, and - Host B may set ECT on data packets. RFC 3168 does not require Host A - to respond properly to data packets received from Host B with the ECT - and CE codepoints set in the IP header. Thus, the data sender, Host - B, might never be informed about the congestion encountered in the - network, thus violating end-to-end congestion control. - - Next we show that if the ECN-related flags in the TCP header are not - zeroed in either the SYN or the SYN/ACK packet, but the firewall does - zero these flags in later packets in that TCP connection, this could - also have the unintended consequence of subverting end-to-end - congestion control for this connection. Figure 4 shows this - scenario. - - - - - - - -Floyd Best Current Practice [Page 17] - -RFC 3360 Inappropriate TCP Resets August 2002 - - - Host A Firewall or router Host B - ----------------------------------------------------------------- - Sends ECN-setup SYN ----------------> Receives ECN-setup SYN - Receives ECN-setup SYN/ACK <------------ Sends ECN-setup SYN/ACK - Sends ACK and data ----------------> Receives ACK and data - <- Sends data packet with ECT - <- Router sets CE - Receives data packet with ECT and CE - Sends ACK with ECE -> - Firewall resets ECE -> - Receives plain ACK - - Figure 4: ECN-related flags in ACK packet cleared in network. - - The ECN-related flags are not changed by the network in the ECN-setup - SYN and SYN/ACK packets for the scenario in Figure 4, and both end - nodes are free to use ECN, and to set the ECT flag in the ECN field - in the IP header. However, if the firewall clears the ECE flag in - the TCP header in ACK packets from Node A to Node B, then Node B will - never hear about the congestion that its earlier data packets - encountered in the network, thus subverting end-to-end congestion - control for this connection. - - Additional complications will arise when/if the use of the ECN nonce - in TCP becomes standardized in the IETF [RFC3168], as this could - involve the specification of an additional flag from the TCP Reserved - field for feedback from the TCP data receiver to the TCP data sender. - The primary motivation for the ECN nonce is to allow mechanisms for - the data sender to verify that network elements are not erasing the - CE codepoint, and that data receivers are properly reporting to the - sender the receipt of packets with the CE codepoint set. - -13. IANA Considerations - - There are no IANA considerations in this document. - -14. Author's Address - - Sally Floyd - ICIR (ICSI Center for Internet Research) - - Phone: +1 (510) 666-2989 - EMail: floyd@icir.org - URL: http://www.icir.org/floyd/ - - - - - - - -Floyd Best Current Practice [Page 18] - -RFC 3360 Inappropriate TCP Resets August 2002 - - -15. Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Floyd Best Current Practice [Page 19] - diff --git a/ext/picotcp/RFC/rfc3366.txt b/ext/picotcp/RFC/rfc3366.txt deleted file mode 100644 index 03753a3..0000000 --- a/ext/picotcp/RFC/rfc3366.txt +++ /dev/null @@ -1,1515 +0,0 @@ - - - - - - -Network Working Group G. Fairhurst -Request for Comments: 3366 University of Aberdeen -BCP: 62 L. Wood -Category: Best Current Practice Cisco Systems Ltd - August 2002 - - - Advice to link designers on link Automatic Repeat reQuest (ARQ) - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document provides advice to the designers of digital - communication equipment and link-layer protocols employing link-layer - Automatic Repeat reQuest (ARQ) techniques. This document presumes - that the designers wish to support Internet protocols, but may be - unfamiliar with the architecture of the Internet and with the - implications of their design choices for the performance and - efficiency of Internet traffic carried over their links. - - ARQ is described in a general way that includes its use over a wide - range of underlying physical media, including cellular wireless, - wireless LANs, RF links, and other types of channel. This document - also describes issues relevant to supporting IP traffic over - physical-layer channels where performance varies, and where link ARQ - is likely to be used. - - - - - - - - - - - - - - - - -Fairhurst & Wood Best Current Practice [Page 1] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - -Table of Contents - - 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . .2 - 1.1 Link ARQ. . . . . . . . . . . . . . . . . . . . . . . . . . .4 - 1.2 Causes of Packet Loss on a Link . . . . . . . . . . . . . . .5 - 1.3 Why Use ARQ?. . . . . . . . . . . . . . . . . . . . . . . . .6 - 1.4 Commonly-used ARQ Techniques. . . . . . . . . . . . . . . . .7 - 1.4.1 Stop-and-wait ARQ . . . . . . . . . . . . . . . . . . . . . .7 - 1.4.2 Sliding-Window ARQ. . . . . . . . . . . . . . . . . . . . . .7 - 1.5 Causes of Delay Across a Link . . . . . . . . . . . . . . . .8 - 2. ARQ Persistence . . . . . . . . . . . . . . . . . . . . . . 10 - 2.1 Perfectly-Persistent (Reliable) ARQ Protocols . . . . . . . 10 - 2.2 High-Persistence (Highly-Reliable) ARQ Protocols. . . . . . 12 - 2.3 Low-Persistence (Partially-Reliable) ARQ Protocols. . . . . 13 - 2.4 Choosing Your Persistency . . . . . . . . . . . . . . . . . 13 - 2.5 Impact of Link Outages. . . . . . . . . . . . . . . . . . . 14 - 3. Treatment of Packets and Flows. . . . . . . . . . . . . . . 15 - 3.1 Packet Ordering . . . . . . . . . . . . . . . . . . . . . . 15 - 3.2 Using Link ARQ to Support Multiple Flows. . . . . . . . . . 16 - 3.3 Differentiation of Link Service Classes . . . . . . . . . . 17 - 4. Conclusions . . . . . . . . . . . . . . . . . . . . . . . . 19 - 5. Security Considerations . . . . . . . . . . . . . . . . . . 21 - 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . 21 - 7. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . 22 - 8. References. . . . . . . . . . . . . . . . . . . . . . . . . 22 - 8.1 Normative References. . . . . . . . . . . . . . . . . . . . 22 - 8.2 Informative References. . . . . . . . . . . . . . . . . . . 23 - 9. Authors' Addresses. . . . . . . . . . . . . . . . . . . . . 26 - 10. Full Copyright Statement. . . . . . . . . . . . . . . . . . 27 - -1. Introduction - - IP, the Internet Protocol [RFC791], forms the core protocol of the - global Internet and defines a simple "connectionless" packet-switched - network. Over the years, Internet traffic using IP has been carried - over a wide variety of links, of vastly different capacities, delays - and loss characteristics. In the future, IP traffic can be expected - to continue to be carried over a very wide variety of new and - existing link designs, again of varied characteristics. - - A companion document [DRAFTKARN02] describes the general issues - associated with link design. This document should be read in - conjunction with that and with other documents produced by the - Performance Implications of Link Characteristics (PILC) IETF - workgroup [RFC3135, RFC3155]. - - - - - - -Fairhurst & Wood Best Current Practice [Page 2] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - This document is intended for three distinct groups of readers: - - a. Link designers wishing to configure (or tune) a link for the IP - traffic that it will carry, using standard link-layer mechanisms - such as the ISO High-level Data Link Control (HDLC) [ISO4335a] or - its derivatives. - - b. Link implementers who may wish to design new link mechanisms that - perform well for IP traffic. - - c. The community of people using or developing TCP, UDP and related - protocols, who may wish to be aware of the ways in which links - can operate. - - The primary audiences are intended to be groups (a) and (b). Group - (c) should not need to be aware of the exact details of an ARQ scheme - across a single link, and should not have to consider such details - for protocol implementations; much of the Internet runs across links - that do not use any form of ARQ. However, the TCP/IP community does - need to be aware that the IP protocol operates over a diverse range - of underlying subnetworks. This document may help to raise that - awareness. - - Perfect reliability is not a requirement for IP networks, nor is it a - requirement for links [DRAFTKARN02]. IP networks may discard packets - due to a variety of reasons entirely unrelated to channel errors, - including lack of queuing space, congestion management, faults, and - route changes. It has long been widely understood that perfect - end-to-end reliability can be ensured only at, or above, the - transport layer [SALT81]. - - Some familiarity with TCP, the Transmission Control Protocol [RFC793, - STE94], is presumed here. TCP provides a reliable byte-stream - transport service, building upon the best-effort datagram delivery - service provided by the Internet Protocol. TCP achieves this by - dividing data into TCP segments, and transporting these segments in - IP packets. TCP guarantees that a TCP session will retransmit the - TCP segments contained in any data packets that are lost along the - Internet path between endhosts. TCP normally performs retransmission - using its Fast Retransmit procedure, but if the loss fails to be - detected (or retransmission is unsuccessful), TCP falls back to a - Retransmission Time Out (RTO) retransmission using a timer [RFC2581, - RFC2988]. (Link protocols also implement timers to verify integrity - of the link, and to assist link ARQ.) TCP also copes with any - duplication or reordering introduced by the IP network. There are a - number of variants of TCP, with differing levels of sophistication in - - - - - -Fairhurst & Wood Best Current Practice [Page 3] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - their procedures for handling loss recovery and congestion avoidance. - Far from being static, the TCP protocol is itself subject to ongoing - gradual refinement and evolution, e.g., [RFC2488, RFC2760]. - - Internet networks may reasonably be expected to carry traffic from a - wide and evolving range of applications. Not all applications - require or benefit from using the reliable service provided by TCP. - In the Internet, these applications are carried by alternate - transport protocols, such as the User Datagram Protocol (UDP) - [RFC768]. - -1.1 Link ARQ - - At the link layer, ARQ operates on blocks of data, known as frames, - and attempts to deliver frames from the link sender to the link - receiver over a channel. The channel provides the physical-layer - connection over which the link protocol operates. In its simplest - form, a channel may be a direct physical-layer connection between the - two link nodes (e.g., across a length of cable or over a wireless - medium). ARQ may also be used edge-to-edge across a subnetwork, - where the path includes more than one physical-layer medium. Frames - often have a small fixed or maximum size for convenience of - processing by Medium-Access Control (MAC) and link protocols. This - contrasts with the variable lengths of IP datagrams, or 'packets'. A - link-layer frame may contain all, or part of, one or more IP packets. - A link ARQ mechanism relies on an integrity check for each frame - (e.g., strong link-layer CRC [DRAFTKARN02]) to detect channel errors, - and uses a retransmission process to retransmit lost (i.e., missing - or corrupted) frames. - - Links may be full-duplex (allowing two-way communication over - separate forward and reverse channels), half-duplex (where two-way - communication uses a shared forward and reverse channel, e.g., IrDA, - IEEE 802.11) or simplex (where a single channel permits communication - in only one direction). - - ARQ requires both a forward and return path, and therefore link ARQ - may be used over links that employ full- or half-duplex links. When - a channel is shared between two or more link nodes, a link MAC - protocol is required to ensure all nodes requiring transmission can - gain access to the shared channel. Such schemes may add to the delay - (jitter) associated with transmission of packet data and ARQ control - frames. - - When using ARQ over a link where the probability of frame loss is - related to the frame size, there is an optimal frame size for any - specific target channel error rate. To allow for efficient use of - the channel, this maximum link frame size may be considerably lower - - - -Fairhurst & Wood Best Current Practice [Page 4] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - than the maximum IP datagram size specified by the IP Maximum - Transmission Unit (MTU). Each frame will then contain only a - fraction of an IP packet, and transparent implicit fragmentation of - the IP datagram is used [DRAFTKARN02]. A smaller frame size - introduces more frame header overhead per payload byte transported. - - Explicit network-layer IP fragmentation is undesirable for a variety - of reasons, and should be avoided [KEN87, DRAFTKARN02]. Its use can - be minimized with use of Path MTU discovery [RFC1191, RFC1435, - RFC1981]. - - Another way to reduce the frame loss rate (or reduce transmit signal - power for the same rate of frame loss) is to use coding, e.g., - Forward Error Correction (FEC) [LIN93]. - - FEC is commonly included in the physical-layer design of wireless - links and may be used simultaneously with link ARQ. FEC schemes - which combine modulation and coding also exist, and may also be - adaptive. Hybrid ARQ [LIN93] combines adaptive FEC with link ARQ - procedures to reduce the probability of loss of retransmitted frames. - Interleaving may also be used to reduce the probability of frame loss - by dispersing the occurrence of errors more widely in the channel to - improve error recovery; this adds further delay to the channel's - existing propagation delay. - - The document does not consider the use of link ARQ to support a - broadcast or multicast service within a subnetwork, where a link may - send a single packet to more than one recipient using a single link - transmit operation. Although such schemes are supported in some - subnetworks, they raise a number of additional issues not examined - here. - - Links supporting stateful reservation-based quality of service (QoS) - according to the Integrated Services (intserv) model are also not - explicitly discussed. - -1.2 Causes of Packet Loss on a Link - - Not all packets sent to a link are necessarily received successfully - by the receiver at the other end of the link. There are a number of - possible causes of packet loss. These may occur as frames travel - across a link, and include: - - a. Loss due to channel noise, often characterised by random frame - loss. Channel noise may also result from other traffic degrading - channel conditions. - - - - - -Fairhurst & Wood Best Current Practice [Page 5] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - b. Frame loss due to channel interference. This interference can - be random, structured, and in some cases even periodic. - - c. A link outage, a period during which the link loses all or - virtually all frames, until the link is restored. This is a - common characteristic of some types of link, e.g., mobile cellular - radio. - - Other forms of packet loss are not related to channel conditions, - but include: - - i. Loss of a frame transmitted in a shared channel where a - contention-aware MAC protocol is used (e.g., due to collision). - Here, many protocols require that retransmission is deferred to - promote stability of the shared channel (i.e., prevent excessive - channel contention). This is discussed further in section 1.5. - - ii. Packet discards due to congestion. Queues will eventually - overflow as the arrival rate of new packets to send continues to - exceed the outgoing packet transmission rate over the link. - - iii. Loss due to implementation errors, including hardware faults - and software errors. This is recognised as a common cause of - packet corruption detected in the endhosts [STONE00]. - - The rate of loss and patterns of loss experienced are functions of - the design of the physical and link layers. These vary significantly - across different link configurations. The performance of a specific - implementation may also vary considerably across the same link - configuration when operated over different types of channel. - -1.3 Why Use ARQ? - - Reasons that encourage considering the use of ARQ include: - - a. ARQ across a single link has a faster control loop than TCP's - acknowledgement control loop, which takes place over the longer - end-to-end path over which TCP must operate. It is therefore - possible for ARQ to provide more rapid retransmission of TCP - segments lost on the link, at least for a reasonable number of - retries [RFC3155, SALT81]. - - b. Link ARQ can operate on individual frames, using implicit - transparent link fragmentation [DRAFTKARN02]. Frames may be - much smaller than IP packets, and repetition of smaller frames - containing lost or errored parts of an IP packet may improve the - efficiency of the ARQ process and the efficiency of the link. - - - - -Fairhurst & Wood Best Current Practice [Page 6] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - A link ARQ procedure may be able to use local knowledge that is not - available to endhosts, to optimise delivery performance for the - current link conditions. This information can include information - about the state of the link and channel, e.g., knowledge of the - current available transmission rate, the prevailing error - environment, or available transmit power in wireless links. - -1.4 Commonly-used ARQ Techniques - - A link ARQ protocol uses a link protocol mechanism to allow the - sender to detect lost or corrupted frames and to schedule - retransmission. Detection of frame loss may be via a link protocol - timer, by detecting missing positive link acknowledgement frames, by - receiving explicit negative acknowledgement frames and/or by polling - the link receiver status. - - Whatever mechanisms are chosen, there are two easily-described - categories of ARQ retransmission process that are widely used: - -1.4.1 Stop-And-Wait ARQ - - A sender using stop-and-wait ARQ (sometimes known as 'Idle ARQ' - [LIN93]) transmits a single frame and then waits for an - acknowledgement from the receiver for that frame. The sender then - either continues transmission with the next frame, or repeats - transmission of the same frame if the acknowledgement indicates that - the original frame was lost or corrupted. - - Stop-and-wait ARQ is simple, if inefficient, for protocol designers - to implement, and therefore popular, e.g., tftp [RFC1350] at the - transport layer. However, when stop-and-wait ARQ is used in the link - layer, it is well-suited only to links with low bandwidth-delay - products. This technique is not discussed further in this document. - -1.4.2 Sliding-Window ARQ - - A protocol using sliding-window link ARQ [LIN93] numbers every frame - with a unique sequence number, according to a modulus. The modulus - defines the numbering base for frame sequence numbers, and the size - of the sequence space. The largest sequence number value is viewed - by the link protocol as contiguous with the first (0), since the - numbering space wraps around. - - - - - - - - - -Fairhurst & Wood Best Current Practice [Page 7] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - TCP is itself a sliding-window protocol at the transport layer - [STE94], so similarities between a link-interface-to-link-interface - protocol and end-to-end TCP may be recognisable. A sliding-window - link protocol is much more complex in implementation than the simpler - stop-and-wait protocol described in the previous section, - particularly if per-flow ordering is preserved. - - At any time the link sender may have a number of frames outstanding - and awaiting acknowledgement, up to the space available in its - transmission window. A sufficiently-large link sender window - (equivalent to or greater than the number of frames sent, or larger - than the bandwidth*delay product capacity of the link) permits - continuous transmission of new frames. A smaller link sender window - causes the sender to pause transmission of new frames until a timeout - or a control frame, such as an acknowledgement, is received. When - frames are lost, a larger window, i.e., more than the link's - bandwidth*delay product, is needed to allow continuous operation - while frame retransmission takes place. - - The modulus numbering space determines the size of the frame header - sequence number field. This sequence space needs to be larger than - the link window size and, if using selective repeat ARQ, larger than - twice the link window size. For continuous operation, the sequence - space should be larger than the product of the link capacity and the - link ARQ persistence (discussed in section 2), so that in-flight - frames can be identified uniquely. - - As with TCP, which provides sliding-window delivery across an entire - end-to-end path rather than across a single link, there are a large - number of variations on the basic sliding-window implementation, with - increased complexity and sophistication to make them suitable for - various conditions. Selective Repeat (SR), also known as Selective - Reject (SREJ), and Go-Back-N, also known as Reject (REJ), are - examples of ARQ techniques using protocols implementing sliding - window ARQ. - -1.5 Causes of Delay Across a Link - - Links and link protocols contribute to the total path delay - experienced between communicating applications on endhosts. Delay - has a number of causes, including: - - a. Input packet queuing and frame buffering at the link head before - transmission over the channel. - - b. Retransmission back-off, an additional delay introduced for - retransmissions by some MAC schemes when operating over a shared - channel to prevent excessive contention. A high level of - - - -Fairhurst & Wood Best Current Practice [Page 8] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - contention may otherwise arise, if, for example, a set of link - receivers all retransmitted immediately after a collision on a - busy shared channel. Link ARQ protocols designed for shared - channels may select a backoff delay, which increases with the - number of attempts taken to retransmit a frame; analogies can be - drawn with end-to-end TCP congestion avoidance at the transport - layer [RFC2581]. In contrast, a link over a dedicated channel - (which has capacity pre-allocated to the link) may send a - retransmission at the earliest possible time. - - c. Waiting for access to the allocated channel when the channel is - shared. There may be processing or protocol-induced delay - before transmission takes place [FER99, PAR00]. - - d. Frame serialisation and transmission processing. These are - functions of frame size and the transmission speed of the link. - - e. Physical-layer propagation time, limited by the speed of - transmission of the signal in the physical medium of the - channel. - - f. Per-frame processing, including the cost of QoS scheduling, - encryption, FEC and interleaving. FEC and interleaving also add - substantial delay and, in some cases, additional jitter. Hybrid - link ARQ schemes [LIN93], in particular, may incur significant - receiver processing delay. - - g. Packet processing, including buffering frame contents at the - link receiver for packet reassembly, before onward transmission - of the packet. - - When link ARQ is used, steps (b), (c), (d), (e), and (f) may be - repeated a number of times, every time that retransmission of a frame - occurs, increasing overall delay for the packet carried in part by - the frame. Adaptive ARQ schemes (e.g., hybrid ARQ using adaptive FEC - codes) may also incur extra per-frame processing for retransmitted - frames. - - It is important to understand that applications and transport - protocols at the endhosts are unaware of the individual delays - contributed by each link in the path, and only see the overall path - delay. Application performance is therefore determined by the - cumulative delay of the entire end-to-end Internet path. This path - may include an arbitrary or even a widely-fluctuating number of - links, where any link may or may not use ARQ. As a result, it is not - possible to state fixed limits on the acceptable delay that a link - can add to a path; other links in the path will add an unknown delay. - - - - -Fairhurst & Wood Best Current Practice [Page 9] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - -2. ARQ Persistence - - ARQ protocols may be characterised by their persistency. Persistence - is the willingness of the protocol to retransmit lost frames to - ensure reliable delivery of traffic across the link. - - A link's retransmission persistency defines how long the link is - allowed to delay a packet, in an attempt to transmit all the frames - carrying the packet and its content over the link, before giving up - and discarding the packet. This persistency can normally be measured - in milliseconds, but may, if the link propagation delay is specified, - be expressed in terms of the maximum number of link retransmission - attempts permitted. The latter does not always map onto an exact - time limit, for the reasons discussed in section 1.5. - - An example of a reliable link protocol that is perfectly persistent - is the ISO HDLC protocol in the Asynchronous Balanced Mode (ABM) - [ISO4335a]. - - A protocol that only retransmits a number of times before giving up - is less persistent, e.g., Ethernet [FER99], IEEE 802.11, or GSM RLP - [RFC2757]. Here, lower persistence also ensures stability and fair - sharing of a shared channel, even when many senders are attempting - retransmissions. - - TCP, STCP [RFC2960] and a number of applications using UDP (e.g., - tftp) implement their own end-to-end reliable delivery mechanisms. - Many TCP and UDP applications, e.g., streaming multimedia, benefit - from timely delivery from lower layers with sufficient reliability, - rather than perfect reliability with increased link delays. - -2.1 Perfectly-Persistent (Reliable) ARQ Protocols - - A perfectly-persistent ARQ protocol is one that attempts to provide a - reliable service, i.e., in-order delivery of packets to the other end - of the link, with no missing packets and no duplicate packets. The - perfectly-persistent ARQ protocol will repeat a lost or corrupted - frame an indefinite (and potentially infinite) number of times until - the frame is successfully received. - - If traffic is going no further than across one link, and losses do - not occur within the endhosts, perfect persistence ensures - reliability between the two link ends without requiring any - higher-layer protocols. This reliability can become - counterproductive for traffic traversing multiple links, as it - duplicates and interacts with functionality in protocol mechanisms at - higher layers [SALT81]. - - - - -Fairhurst & Wood Best Current Practice [Page 10] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - Arguments against the use of perfect persistence for IP traffic - include: - - a. Variable link delay; the impact of ARQ introduces a degree of - jitter, a function of the physical-layer delay and frame - serialisation and transmission times (discussed in section 1.5), - to all flows sharing a link performing frame retransmission. - - b. Perfect persistence does not provide a clear upper bound on the - maximum retransmission delay for the link. Significant changes - in path delay caused by excessive link retransmissions may lead - to timeouts of TCP retransmission timers, although a high - variance in link delay and the resulting overall path delay may - also cause a large TCP RTO value to be selected [LUD99b, PAR00]. - This will alter TCP throughput, decreasing overall performance, - but, in mitigation, it can also decrease the occurrence of - timeouts due to continued packet loss. - - c. Applications needing perfectly-reliable delivery can implement a - form of perfectly-persistent ARQ themselves, or use a reliable - transport protocol within the endhosts. Implementing perfect - persistence at each link along the path between the endhosts is - redundant, but cannot ensure the same reliability as end-to-end - transport [SALT81]. - - d. Link ARQ should not adversely delay the flow of end-to-end - control information. As an example, the ARQ retransmission of - data for one or more flows should not excessively extend the - protocol control loops. Excessive delay of duplicate TCP - acknowledgements (dupacks [STE94, BAL97]), SACK, or Explicit - Congestion Notification (ECN) indicators will reduce the - responsiveness of TCP flows to congestion events. Similar - issues exist for TCP-Friendly Rate Control (TFRC), where - equation-based congestion control is used with UDP [DRAFTHAN01]. - - Perfectly-persistent link protocols that perform unlimited ARQ, i.e., - that continue to retransmit frames indefinitely until the frames are - successfully received, are seldom found in real implementations. - - Most practical link protocols give up retransmission at some point, - but do not necessarily do so with the intention of bounding the ARQ - retransmission persistence. A protocol may, for instance, terminate - retransmission after a link connection failure, e.g., after no frames - have been successfully received within a pre-configured timer period. - The number of times a protocol retransmits a specific frame (or the - maximum number of retransmissions) therefore becomes a function of - many different parameters (ARQ procedure, link timer values, and - procedure for link monitoring), rather than being pre-configured. - - - -Fairhurst & Wood Best Current Practice [Page 11] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - Another common feature of this type of behaviour is that some - protocol implementers presume that, after a link failure, packets - queued to be sent over the link are no longer significant and can be - discarded when giving up ARQ retransmission. - - Examples of ARQ protocols that are perfectly persistent include - ISO/ITU-T LAP-B [ISO7776] and ISO HDLC in the Asynchronously Balanced - Mode (ABM) [ISO4335a], e.g., using Multiple Selective Reject (MSREJ - [ISO4335b]). These protocols will retransmit a frame an unlimited - number of times until receipt of the frame is acknowledged. - -2.2 High-Persistence (Highly-Reliable) ARQ Protocols - - High-persistence ARQ protocols limit the number of times (or number - of attempts) that ARQ may retransmit a particular frame before the - sender gives up on retransmission of the missing frame and moves on - to forwarding subsequent buffered in-sequence frames. Ceasing - retransmission of a frame does not imply a lack of link connectivity - and does not cause a link protocol state change. - - It has been recommended that a single IP packet should never be - delayed by the network for more than the Maximum Segment Lifetime - (MSL) of 120 seconds defined for TCP [RFC1122]. It is, however, - difficult in practice to bound the maximum path delay of an Internet - path. One case where segment (packet) lifetime may be significant is - where alternate paths of different delays exist between endhosts and - route flapping or flow-unaware traffic engineering is used. Some TCP - packets may follow a short path, while others follow a much longer - path, e.g., using persistent ARQ over a link outage. - - Failure to limit the maximum packet lifetime can result in TCP - sequence numbers wrapping at high transmission rates, where old data - segments may be confused with newer segments if the sequence number - space has been exhausted and reused in the interim. Some TCP - implementations use the Round Trip Timestamp Measurement (RTTM) - option in TCP packets to remove this ambiguity, using the Protection - Against Wrapped Sequence number (PAWS) algorithm [RFC1323]. - - In practice, the MSL is usually very large compared to the typical - TCP RTO. The calculation of TCP RTO is based on estimated round-trip - path delay [RFC2988]. If the number of link retransmissions causes a - path delay larger than the value of RTO, the TCP retransmission timer - can expire, leading to a timeout and retransmission of a segment - (packet) by the TCP sender. - - - - - - - -Fairhurst & Wood Best Current Practice [Page 12] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - Although high persistency may benefit bulk flows, the additional - delay (and variations in delay) that it introduces may be highly - undesirable for other types of flows. Being able to treat flows - separately, with different classes of link service, is useful, and is - discussed in section 3. - - Examples of high-persistence ARQ protocols include [BHA97, ECK98, - LUD99a, MEY99]. - -2.3 Low-Persistence (Partially-Reliable) ARQ Protocols - - The characteristics of a link using a low-persistence ARQ protocol - may be summarised as: - - a. The link is not perfectly reliable and does not provide an - absolute guarantee of delivery, i.e., the transmitter will - discard some frames as it 'gives up' before receiving an - acknowledgement of successful transmission across the link. - - b. There is a lowered limit on the maximum added delay that IP - packets will experience when travelling across the link - (typically lower than the TCP path RTO). This reduces - interaction with TCP timers or with UDP-based error-control - schemes. - - c. The link offers a low bound for the time that retransmission for - any one frame can block completed transmission and assembly of - other correctly and completely-received IP packets whose - transmission was begun before the missing frame was sent. - Limiting delay avoids aggravating contention or interaction - between different packet flows (see also section 3.2). - - Examples of low-persistence ARQ protocols include [SAM96, WARD95, - CHE00]. - -2.4 Choosing Your Persistency - - The TCP Maximum RTO is an upper limit on the maximum time that TCP - will wait until it performs a retransmission. Most TCP - implementations will generally have a TCP RTO of at least several - times the path delay. - - Setting a lower link persistency (e.g., of the order 2-5 - retransmission attempts) reduces potential interaction with the TCP - RTO timer, and may therefore reduce the probability of duplicate - copies of the same packet being present in the link transmit buffer - under some patterns of loss. - - - - -Fairhurst & Wood Best Current Practice [Page 13] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - A link using a physical layer with a low propagation delay may allow - tens of retransmission attempts to deliver a single frame, and still - satisfy a bound for (b) in section 2.3. In this case, a low delay is - defined as being where the total packet transmission time across the - link is much less than 100 ms (a common value for the granularity of - the internal TCP system timer). - - A packet may traverse a number of successive links on its total end- - to-end path. This is therefore an argument for much lower - persistency on any individual link, as delay due to persistency is - accumulated along the path taken by each packet. - - Some implementers have chosen a lower persistence, falling back on - the judgement of TCP or of a UDP application to retransmit any - packets that are not recovered by the link ARQ protocol. - -2.5 Impact of Link Outages - - Links experiencing persistent loss, where many consecutive frames are - corrupted over an extended time, may also need to be considered. - Examples of channel behaviour leading to link outages include fading, - roaming, and some forms of interference. During the loss event, - there is an increased probability that a retransmission request may - be corrupted, and/or an increased probability that a retransmitted - frame will also be lost. This type of loss event is often known as a - "transient outage". - - If the transient outage extends for longer than the TCP RTO, the TCP - sender will also perform transport-layer retransmission. At the same - time, the TCP sender will reduce its congestion window (cwnd) to 1 - segment (packet), recalculate its RTO, and wait for an ACK packet. - If no acknowledgement is received, TCP will retransmit again, up to a - retry limit. TCP only determines that the outage is over (i.e., that - path capacity is restored) by receipt of an ACK. If link ARQ - protocol persistency causes a link in the path to discard the ACK, - the TCP sender must wait for the next RTO retransmission and its ACK - to learn that the link is restored. This can be many seconds after - the end of the transient outage. - - When a link layer is able to differentiate a set of link service - classes (see section 3.3), a link ARQ persistency longer than the - largest link loss event may benefit a TCP session. This would allow - TCP to rapidly restore transmission without the need to wait for a - retransmission time out, generally improving TCP performance in the - face of transient outages. Implementation of such schemes remains a - research issue. - - - - - -Fairhurst & Wood Best Current Practice [Page 14] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - When an outage occurs for a sender sharing a common channel with - other nodes, uncontrolled high persistence can continue to consume - transmission resources for the duration of the outage. This may be - undesirable, since it reduces the capacity available for other nodes - sharing the channel, which do not necessarily experience the same - outage. These nodes could otherwise use the channel for more - productive transfers. The persistence is often limited by another - controlling mechanism in such cases. To counter such contention - effects, ARQ protocols may delay retransmission requests, or defer - the retransmission of requested frames until the outage ends for the - sender. - - An alternate suggested approach for a link layer that is able to - identify separate flows is to use low link persistency (section 2.3) - along with a higher-layer mechanism, for example one that attempts to - deliver one packet (or whole TCP segment) per TCP flow after a loss - event [DRAFTKARN02]. This is intended to ensure that TCP - transmission is restored rapidly. Algorithms to implement this - remain an area of research. - -3. Treatment of Packets and Flows - -3.1 Packet Ordering - - A common debate is whether a link should be allowed to forward - packets in an order different from that in which they were originally - received at its transmit interface. - - IP networks are not required to deliver all IP packets in order, - although in most cases networks do deliver IP packets in their - original transmission order. Routers supporting class-based queuing - do reorder received packets, by reordering packets in different - flows, but these usually retain per-flow ordering. - - Policy-based queuing, allowing fairer access to the link, may also - reorder packets. There is still much debate on optimal algorithms, - and on optimal queue sizes for particular link speeds. This, - however, is not related to the use of link ARQ and applies to any - (potential) bottleneck router. - - Although small amounts of reordering are common in IP networks - [BEN00], significant reordering within a flow is undesirable as it - can have a number of effects: - - a. Reordering will increase packet jitter for real-time - applications. This may lead to application data loss if a small - play-out buffer is used by the receiving application. - - - - -Fairhurst & Wood Best Current Practice [Page 15] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - b. Reordering will interleave arrival of TCP segments, leading to - generation of duplicate ACKs (dupacks), leading to assumptions - of loss. Reception of an ACK followed by a sequence of three - identical dupacks causes the TCP sender to trigger fast - retransmission and recovery, a form of congestion avoidance, - since TCP always presumes that packet loss is due to congestion - [RFC2581, STE94]. This reduces TCP throughput efficiency as far - as the application is concerned, although it should not impact - data integrity. - - In addition, reordering may negatively impact processing by some - existing poorly-implemented TCP/IP stacks, by leading to unwanted - side-effects in poorly-implemented IP fragment reassembly code, - poorly-implemented IP demultiplexing (filter) code, or in - poorly-implemented UDP applications. - - Ordering effects must also be considered when breaking the end-to-end - paradigm and evaluating transport-layer relays such as split-TCP - implementations or Protocol Enhancing Proxies [RFC3135]. - - As with total path delay, TCP and UDP flows are impacted by the - cumulative effect of reordering along the entire path. Link protocol - designers must not assume that their link is the only link - undertaking packet reordering, as some level of reordering may be - introduced by other links along the same path, or by router - processing within the network [BEN00]. Ideally, the link protocol - should not contribute to reordering within a flow, or at least ensure - that it does not significantly increase the level of reordering - within the flow. To achieve this, buffering is required at the link - receiver. The total amount of buffering required is a function of - the link's bandwidth*delay product and the level of ARQ persistency, - and is bounded by the link window size. - - A number of experimental ARQ protocols have allowed out-of-order - delivery [BAL95, SAM96, WARD95]. - -3.2 Using Link ARQ to Support Multiple Flows - - Most links can be expected to carry more than one IP flow at a time. - Some high-capacity links are expected to carry a very large number of - simultaneous flows, often from and to a large number of different - endhosts. With use of multiple applications at an endhost, multiple - flows can be considered the norm rather than the exception, even for - last-hop links. - - - - - - - -Fairhurst & Wood Best Current Practice [Page 16] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - When packets from several flows are simultaneously in transit within - a link ARQ protocol, ARQ may cause a number of additional effects: - - a. ARQ introduces variable delay (jitter) to a TCP flow sharing a - link with another flow experiencing loss. This additional - delay, introduced by the need for a link to provide in-sequence - delivery of packets, may adversely impact other applications - sharing the link, and can increase the duration of the initial - slow-start period for TCP flows for these applications. This is - significant for short-lived TCP flows (e.g., those used by - HTTP/1.0 and earlier), which spend most of their lives in - slow-start. - - b. ARQ introduces jitter to UDP flows that share a link with - another flow experiencing loss. An end-to-end protocol may not - require reliable delivery for its flows, particularly if it is - supporting a delay-sensitive application. - - c. High-persistence ARQ may delay packets long enough to cause the - premature timeout of another TCP flow's RTO timer, although - modern TCP implementations should not experience this since - their computed RTO values should leave a sufficient margin over - path RTTs to cope with reasonable amounts of jitter. - - Reordering of packets belonging to different flows may be desirable - [LUD99b, CHE00] to achieve fair sharing of the link between - established bulk-data transfer sessions and sessions that transmit - less data, but would benefit from lower link transit delay. - Preserving ordering within each individual flow, to avoid the effects - of reordering described earlier in section 3.1, is worthwhile. - -3.3 Differentiation of Link Service Classes - - High ARQ persistency is generally considered unsuitable for many - applications using UDP, where reliable delivery is not always - required and where it may introduce unacceptable jitter, but may - benefit bulk data transfers under certain link conditions. A scheme - that differentiates packet flows into two or more classes, to provide - a different service to each class, is therefore desirable. - - Observation of flow behaviour can tell you which flows are controlled - and congestion-sensitive, or uncontrolled and not, so that you can - treat them differently and ensure fairness. However, this cannot - tell you whether a flow is intended as reliable or unreliable by its - application, or what the application requires for best operation. - - - - - - -Fairhurst & Wood Best Current Practice [Page 17] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - Supporting different link services for different classes of flows - therefore requires that the link is able to distinguish the different - flows from each other. This generally needs an explicit indication - of the class associated with each flow. - - Some potential schemes for indicating the class of a packet include: - - a. Using the Type of Service (ToS) bits in the IP header [RFC791]. - The IETF has replaced these globally-defined bits, which were - not widely used, with the differentiated services model - (diffserv [RFC2475, RFC3260]). In diffserv, each packet carries a - Differentiated Service Code Point (DSCP), which indicates which - one of a set of diffserv classes the flow belongs to. Each - router maps the DSCP value of a received IP packet to one of a - set of Per Hop Behaviours (PHBs) as the packet is processed - within the network. Diffserv uses include policy-based routing, - class-based queuing, and support for other QoS metrics, - including IP packet priority, delay, reliability, and cost. - - b. Inspecting the network packet header and viewing the IP protocol - type [RFC791] to gain an idea of the transport protocol used and - thus guess its needs. This is not possible when carrying an - encrypted payload, e.g., using the IP security extensions (IPSec) - with Encapsulation Security Payload (ESP) [RFC2406] payload - encryption. - - c. By inspecting the transport packet header information to view - the TCP or UDP headers and port numbers (e.g., [PAR00, BAL95]). - This is not possible when using payload encryption, e.g., IPSec - with ESP payload encryption [RFC2406], and incurs processing - overhead for each packet sent over the link. - - There are, however, some drawbacks to these schemes: - - i. The ToS/Differentiated Services Code Point (DSCP) values - [RFC2475] may not be set reliably, and may be overwritten by - intermediate routers along the packet's path. These values may - be set by an ISP, and do not necessarily indicate the level of - reliability required by the end application. The link must be - configured with knowledge of the local meaning of the values. - - ii. Tunnelling of traffic (e.g., GRE, MPLS, L2TP, IP-in-IP - encapsulation) can aggregate flows of different transport - classes, complicating individual flow classification with - schemes (b) and (c) and incurring further header processing if - tunnel contents are inspected. - - - - - -Fairhurst & Wood Best Current Practice [Page 18] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - iii. Use of the TCP/UDP port number makes assumptions about - application behaviour and requirements. New applications or - protocols can invalidate these assumptions, as can the use of - e.g., Network Address Port Translation, where port numbers are - remapped [RFC3022]. - - iv. In IPv6, the entire IPv6 header must be parsed to locate the - transport layer protocol, adding complexity to header - inspection. Again, this assumes that IPSec payload encryption - is not used. - - Despite the difficulties in providing a framework for accurate flow - identification, approach (a) may be beneficial, and is preferable to - adding optimisations that are triggered by inspecting the contents of - specific IP packets. Some such optimisations are discussed in detail - in [LUD99b]. - - Flow management is desirable; clear flow identification increases the - number of tools available for the link designer, and permits more - complex ARQ strategies that may otherwise make misassumptions about - traffic requirements and behaviour when flow identification is not - done. - - Links that are unable to distinguish clearly and safely between - delay-sensitive flows, e.g., real-time multimedia, DNS queries or - telnet, and delay-insensitive flows, e.g., bulk ftp transfers or - reliable multicast file transfer, cannot separate link service - classes safely. All flows should therefore experience the same link - behaviour. - - In general, if separation of flows according to class is not - practicable, a low persistency is best for link ARQ. - -4. Conclusions - - A number of techniques may be used by link protocol designers to - counter the effects of channel errors or loss. One of these - techniques is Automatic Repeat ReQuest, ARQ, which has been and - continues to be used on links that carry IP traffic. An ARQ protocol - retransmits link frames that have been corrupted during transmission - across a channel. Link ARQ may significantly improve the probability - of successful transmission of IP packets over links prone to - occasional frame loss. - - A lower rate of packet loss generally benefits transport protocols - and endhost applications. Applications using TCP generally benefit - from Internet paths with little or no loss and low round trip path - delay. This reduces impact on applications, allows more rapid growth - - - -Fairhurst & Wood Best Current Practice [Page 19] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - of TCP's congestion window during slow start, and ensures prompt - reaction to end-to-end protocol exchanges (e.g., retransmission, - congestion indications). Applications using other transport - protocols, e.g., UDP or SCTP, also benefit from low loss and timely - delivery. - - A side-effect of link ARQ is that link transit delay is increased - when frames are retransmitted. At low error rates, many of the - details of ARQ, such as degree of persistence or any resulting - out-of-order delivery, become unimportant. Most frame losses will be - resolved in one or two retransmission attempts, and this is generally - unlikely to cause significant impact to e.g., TCP. However, on - shared high-delay links, the impact of ARQ on other UDP or TCP flows - may lead to unwanted jitter. - - Where error rates are highly variable, high link ARQ persistence may - provide good performance for a single TCP flow. However, - interactions between flows can arise when many flows share capacity - on the same link. A link ARQ procedure that provides flow management - will be beneficial. Lower ARQ persistence may also have merit, and - is preferable for applications using UDP. The reasoning here is that - the link can perform useful work forwarding some complete packets, - and that blocking all flows by retransmitting the frames of a single - packet with high persistence is undesirable. - - During a link outage, interactions between ARQ and multiple flows are - less significant; the ARQ protocol is likely to be equally - unsuccessful in retransmitting frames for all flows. High - persistence may benefit TCP flows, by enabling prompt recovery once - the channel is restored. - - Low ARQ persistence is particularly useful where it is difficult or - impossible to classify traffic flows, and hence treat each flow - independently, and where the link capacity can accommodate a large - number of simultaneous flows. - - Link ARQ designers should consider the implications of their design - on the wider Internet. Effects such as increased transit delay, - jitter, and re-ordering are cumulative when performed on multiple - links along an Internet path. It is therefore very hard to say how - many ARQ links may exist in series along an arbitrary Internet path - between endhosts, especially as the path taken and its links may - change over time. - - In summary, when links cannot classify traffic flows and treat them - separately, low persistence is generally desirable; preserving packet - ordering is generally desirable. Extremely high persistence and - perfect persistence are generally undesirable; highly-persistent ARQ - - - -Fairhurst & Wood Best Current Practice [Page 20] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - is a bad idea unless flow classification and detailed and accurate - knowledge of flow requirements make it possible to deploy high - persistency where it will be beneficial. - - There is currently insufficient experience to recommend a specific - ARQ scheme for any class of link. It is also important to realize - that link ARQ is just one method of error recovery, and that other - complementary physical-layer techniques may be used instead of, or - together with, ARQ to improve overall link throughput for IP traffic. - - The choice of potential schemes includes adapting the data rate, - adapting the signal bandwidth, adapting the transmission power, - adaptive modulation, adaptive information redundancy / forward error - control, and interleaving. All of these schemes can be used to - improve the received signal energy per bit, and hence reduce error, - frame loss and resulting packet loss rates given specific channel - conditions. - - There is a need for more research to more clearly identify the - importance of and trade-offs between the above issues over various - types of link and over various types of channels. It would be useful - if researchers and implementers clearly indicated the loss model, - link capacity and characteristics, link and end-to-end path delays, - details of TCP, and the number (and details) of flows sharing a link - when describing their experiences. In each case, it is recommended - that specific details of the link characteristics and mechanisms also - be considered; solutions vary with conditions. - -5. Security Considerations - - No security implications have been identified as directly impacting - IP traffic. However, an unreliable link service may adversely impact - some existing link-layer key management distribution protocols if - link encryption is also used over the link. - - Denial-of-service attacks exploiting the behaviour of the link - protocol, e.g., using knowledge of its retransmission behaviour and - propagation delay to cause a particular form of jamming, may be - specific to an individual link scenario. - -6. IANA Considerations - - No assignments from the IANA are required. - - - - - - - - -Fairhurst & Wood Best Current Practice [Page 21] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - -7. Acknowledgements - - Much of what is described here has been developed from a summary of a - subset of the discussions on the archived IETF PILC mailing list. We - thank the contributors to PILC for vigorous debate. - - In particular, the authors would like to thank Spencer Dawkins, Aaron - Falk, Dan Grossman, Merkourios Karaliopoulos, Gary Kenward, Reiner - Ludwig and Jean Tourrilhes for their detailed comments. - -8. References - - References of the form RFCnnnn are Internet Request for Comments - (RFC) documents available online at http://www.rfc-editor.org/. - -8.1 Normative References - - [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", RFC 793, - September 1981. - - [RFC1122] Braden, R., Ed., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC2406] Kent, S. and R. Atkinson, "IP Encapsulating Security - Payload (ESP)", RFC 2406, November 1998. - - [RFC2475] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z. - and W. Weiss, "An Architecture for Differentiated - Services", RFC 2475, December 1998. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's - Retransmission Timer", RFC 2988, November 2000. - - [RFC3135] Border, J., Kojo, M., Griner, J., Montenegro, G. and Z. - Shelby, "Performance Enhancing Proxies Intended to - Mitigate Link-Related Degradations", RFC 3135, June - 2001. - - - - - -Fairhurst & Wood Best Current Practice [Page 22] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - [RFC3260] Grossman, D., "New Terminology and Clarifications for - Diffserv", RFC 3260, April 2002. - -8.2 Informative References - - [BAL95] Balakrishnan, H., Seshan, S. and R. H. Katz, - "Improving Reliable Transport and Handoff Performance - in Cellular Wireless Networks", ACM MOBICOM, Berkeley, - 1995. - - [BAL97] Balakrishnan, H., Padmanabhan, V. N., Seshan, S. and - R. H. Katz, "A Comparison of Mechanisms for Improving - TCP Performance over Wireless Links", IEEE/ACM - Transactions on Networking, 5(6), pp. 756-759, 1997. - - [BEN00] Bennett, J. C., Partridge, C. and N. Schectman, "Packet - Reordering is Not Pathological Network Behaviour", - IEEE/ACM Transactions on Networking, 7(6), pp. 789-798, - 2000. - - [BHA97] Bhagwat, P., Bhattacharya, P., Krishna A. and S. K. - Tripathi, "Using channel state dependent packet - scheduling to improve TCP throughput over wireless - LANs", ACM/Baltzer Wireless Networks Journal, (3)1, - 1997. - - [CHE00] Cheng, H. S., G. Fairhurst et al., "An Efficient - Partial Retransmission ARQ Strategy with Error Codes - by Feedback Channel", IEE Proceedings - Communications, - (147)5, pp. 263-268, 2000. - - [DRAFTKARN02] Karn, P., Ed., "Advice for Internet Subnetwork - Designers", Work in Progress. - - [DRAFTHAN01] Handley, M., Floyd, S. and J. Widmer, "TCP Friendly - Rate Control (TFRC): Protocol Specification", Work in - Progress. - - [ECK98] Eckhardt, D. A. and P. Steenkiste, "Improving Wireless - LAN Performance via Adaptive Local Error Control", - IEEE ICNP, 1998. - - [FER99] Ferrero, A., "The Eternal Ethernet", Addison-Wesley, - 1999. - - [ISO4335a] HDLC Procedures: Specification for Consolidation of - Elements of Procedures, ISO 4335 and AD/1, - International Standardization Organization, 1985. - - - -Fairhurst & Wood Best Current Practice [Page 23] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - [ISO4335b] HDLC Procedures: Elements of Procedures, Amendment 4: - Multi-Selective Reject Option, ISO 4335/4, - International Standards Organization, 1991. - - [ISO7776] Specification for X.25 LAPB-Compatible DTE Data Link - Procedures, ISO 4335/4, International Standards - Organization, 1985. - - [KEN87] Kent, C. A. and J. C. Mogul, "Fragmentation - Considered Harmful", Proceedings of ACM SIGCOMM 1987, - ACM Computer Communications Review, 17(5), pp. 390-401, - 1987. - - [LIN93] Lin, S. and D. Costello, "Error Control Coding: - Fundamentals and Applications", Prentice Hall, 1993. - - [LUD99a] Ludwig, R., Rathonyi, B., Konrad, A., Oden, K., and A. - Joseph, "Multi-Layer Tracing of TCP over a Reliable - Wireless Link", ACM SIGMETRICS, pp. 144-154, 1999. - - [LUD99b] Ludwig, R., Konrad, A., Joseph, A. and R. H. Katz, - "Optimizing the End-to-End Performance of Reliable - Flows over Wireless Links", ACM MobiCOM, 1999. - - [MEY99] Meyer, M., "TCP Performance over GPRS", IEEE Wireless - Communications and Networking Conference, 1999. - - [PAR00] Parsa, C. and J. J. Garcia-Luna-Aceves, "Improving TCP - Performance over Wireless Networks at the Link Layer", - ACM Mobile Networks and Applications Journal, (5)1, - pp. 57-71, 2000. - - [RFC1191] Mogul, J. and S. Deering, "Path MTU Discovery", RFC - 1191, November 1990. - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [RFC1350] Sollins, K., "The TFTP Protocol (Revision 2)", STD 33, - RFC 1350, July 1992. - - [RFC1435] Knowles, S., "IESG Advice from Experience with Path MTU - Discovery", RFC 1435, March 1993. - - [RFC1981] McCann, J., Deering, S. and J. Mogul, "Path MTU - Discovery for IP version 6", RFC 1981, August 1996. - - - - - -Fairhurst & Wood Best Current Practice [Page 24] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - [RFC2488] Allman, M., Glover, D. and L. Sanchez, "Enhancing TCP - Over Satellite Channels using Standard Mechanisms", - BCP 28, RFC 2488, January 1999. - - [RFC2757] Montenegro, G., Dawkins, S., Kojo, M., Magret V. and - N. Vaidya, "Long Thin Networks", RFC 2757, January - 2000. - - [RFC2760] Allman, M., Dawkins, S., Glover, D., Griner, J., - Tran, D., Henderson, T., Heidemann, J., Touch, J., - Kruse, H., Ostermann, S., Scott K. and J. Semke - "Ongoing TCP Research Related to Satellites", - RFC 2760, February 2000. - - [RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C., - Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., - Zhang, L. and V. Paxson, "Stream Control Transmission - Protocol", RFC 2960, October 2000. - - [RFC3022] Srisuresh, P. and K. Egevang, "Traditional IP Network - Address Translator (Traditional NAT)", RFC 3022, - January 2001. - - [RFC3155] Dawkins, S., Montenegro, G., Kojo, M., Magret, V. and - N. Vaidya, "End-to-end Performance Implications of - Links with Errors", BCP 50, RFC 3155, August 2001. - - [SALT81] Saltzer, J. H., Reed, D. P. and D. Clark, "End-to-End - Arguments in System Design", Second International - Conference on Distributed Computing Systems, pp. - 509-512, 1981. Published with minor changes in ACM - Transactions in Computer Systems (2)4, pp. 277-288, - 1984. - - [SAM96] Samaraweera, N. and G. Fairhurst, "Robust Data Link - Protocols for Connection-less Service over Satellite - Links", International Journal of Satellite - Communications, 14(5), pp. 427-437, 1996. - - [SAM98] Samaraweera, N. and G. Fairhurst, "Reinforcement of - TCP/IP Error Recovery for Wireless Communications", - ACM Computer Communications Review, 28(2), pp. 30-38, - 1998. - - [STE94] Stevens, W. R., "TCP/IP Illustrated, Volume 1", - Addison-Wesley, 1994. - - - - - -Fairhurst & Wood Best Current Practice [Page 25] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - - [STONE00] Stone, J. and C. Partridge, "When the CRC and TCP - Checksum Disagree", Proceedings of SIGCOMM 2000, ACM - Computer Communications Review 30(4), pp. 309-321, - September 2000. - - [WARD95] Ward, C., et al., "A Data Link Control Protocol for LEO - Satellite Networks Providing a Reliable Datagram - Service", IEEE/ACM Transactions on Networking, 3(1), - 1995. - -Authors' Addresses - - Godred Fairhurst - Department of Engineering - University of Aberdeen - Aberdeen AB24 3UE - United Kingdom - - EMail: gorry@erg.abdn.ac.uk - http://www.erg.abdn.ac.uk/users/gorry/ - - - Lloyd Wood - Cisco Systems Ltd - 4 The Square - Stockley Park - Uxbridge UB11 1BY - United Kingdom - - EMail: lwood@cisco.com - http://www.ee.surrey.ac.uk/Personal/L.Wood/ - - - - - - - - - - - - - - - - - - - - -Fairhurst & Wood Best Current Practice [Page 26] - -RFC 3366 Advice to Link Designers on Link ARQ August 2002 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Fairhurst & Wood Best Current Practice [Page 27] - diff --git a/ext/picotcp/RFC/rfc3390.txt b/ext/picotcp/RFC/rfc3390.txt deleted file mode 100644 index 968a340..0000000 --- a/ext/picotcp/RFC/rfc3390.txt +++ /dev/null @@ -1,843 +0,0 @@ - - - - - - -Network Working Group M. Allman -Request for Comments: 3390 BBN/NASA GRC -Obsoletes: 2414 S. Floyd -Updates: 2581 ICIR -Category: Standards Track C. Partridge - BBN Technologies - October 2002 - - - Increasing TCP's Initial Window - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document specifies an optional standard for TCP to increase the - permitted initial window from one or two segment(s) to roughly 4K - bytes, replacing RFC 2414. It discusses the advantages and - disadvantages of the higher initial window, and includes discussion - of experiments and simulations showing that the higher initial window - does not lead to congestion collapse. Finally, this document - provides guidance on implementation issues. - -Terminology - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in RFC 2119 [RFC2119]. - -1. TCP Modification - - This document obsoletes [RFC2414] and updates [RFC2581] and specifies - an increase in the permitted upper bound for TCP's initial window - from one or two segment(s) to between two and four segments. In most - cases, this change results in an upper bound on the initial window of - roughly 4K bytes (although given a large segment size, the permitted - initial window of two segments may be significantly larger than 4K - bytes). - - - -Allman, et. al. Standards Track [Page 1] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - The upper bound for the initial window is given more precisely in - (1): - - min (4*MSS, max (2*MSS, 4380 bytes)) (1) - - Note: Sending a 1500 byte packet indicates a maximum segment size - (MSS) of 1460 bytes (assuming no IP or TCP options). Therefore, - limiting the initial window's MSS to 4380 bytes allows the sender to - transmit three segments initially in the common case when using 1500 - byte packets. - - Equivalently, the upper bound for the initial window size is based on - the MSS, as follows: - - If (MSS <= 1095 bytes) - then win <= 4 * MSS; - If (1095 bytes < MSS < 2190 bytes) - then win <= 4380; - If (2190 bytes <= MSS) - then win <= 2 * MSS; - - This increased initial window is optional: a TCP MAY start with a - larger initial window. However, we expect that most general-purpose - TCP implementations would choose to use the larger initial congestion - window given in equation (1) above. - - This upper bound for the initial window size represents a change from - RFC 2581 [RFC2581], which specified that the congestion window be - initialized to one or two segments. - - This change applies to the initial window of the connection in the - first round trip time (RTT) of data transmission following the TCP - three-way handshake. Neither the SYN/ACK nor its acknowledgment - (ACK) in the three-way handshake should increase the initial window - size above that outlined in equation (1). If the SYN or SYN/ACK is - lost, the initial window used by a sender after a correctly - transmitted SYN MUST be one segment consisting of MSS bytes. - - TCP implementations use slow start in as many as three different - ways: (1) to start a new connection (the initial window); (2) to - restart transmission after a long idle period (the restart window); - and (3) to restart transmission after a retransmit timeout (the loss - window). The change specified in this document affects the value of - the initial window. Optionally, a TCP MAY set the restart window to - the minimum of the value used for the initial window and the current - value of cwnd (in other words, using a larger value for the restart - window should never increase the size of cwnd). These changes do NOT - change the loss window, which must remain 1 segment of MSS bytes (to - - - -Allman, et. al. Standards Track [Page 2] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - permit the lowest possible window size in the case of severe - congestion). - -2. Implementation Issues - - When larger initial windows are implemented along with Path MTU - Discovery [RFC1191], and the MSS being used is found to be too large, - the congestion window `cwnd' SHOULD be reduced to prevent large - bursts of smaller segments. Specifically, `cwnd' SHOULD be reduced - by the ratio of the old segment size to the new segment size. - - When larger initial windows are implemented along with Path MTU - Discovery [RFC1191], alternatives are to set the "Don't Fragment" - (DF) bit in all segments in the initial window, or to set the "Don't - Fragment" (DF) bit in one of the segments. It is an open question as - to which of these two alternatives is best; we would hope that - implementation experiences will shed light on this question. In the - first case of setting the DF bit in all segments, if the initial - packets are too large, then all of the initial packets will be - dropped in the network. In the second case of setting the DF bit in - only one segment, if the initial packets are too large, then all but - one of the initial packets will be fragmented in the network. When - the second case is followed, setting the DF bit in the last segment - in the initial window provides the least chance for needless - retransmissions when the initial segment size is found to be too - large, because it minimizes the chances of duplicate ACKs triggering - a Fast Retransmit. However, more attention needs to be paid to the - interaction between larger initial windows and Path MTU Discovery. - - The larger initial window specified in this document is not intended - as encouragement for web browsers to open multiple simultaneous TCP - connections, all with large initial windows. When web browsers open - simultaneous TCP connections to the same destination, they are - working against TCP's congestion control mechanisms [FF99], - regardless of the size of the initial window. Combining this - behavior with larger initial windows further increases the unfairness - to other traffic in the network. We suggest the use of HTTP/1.1 - [RFC2068] (persistent TCP connections and pipelining) as a way to - achieve better performance of web transfers. - -3. Advantages of Larger Initial Windows - - 1. When the initial window is one segment, a receiver employing - delayed ACKs [RFC1122] is forced to wait for a timeout before - generating an ACK. With an initial window of at least two - segments, the receiver will generate an ACK after the second data - segment arrives. This eliminates the wait on the timeout (often - up to 200 msec, and possibly up to 500 msec [RFC1122]). - - - -Allman, et. al. Standards Track [Page 3] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - 2. For connections transmitting only a small amount of data, a - larger initial window reduces the transmission time (assuming at - most moderate segment drop rates). For many email (SMTP [Pos82]) - and web page (HTTP [RFC1945, RFC2068]) transfers that are less - than 4K bytes, the larger initial window would reduce the data - transfer time to a single RTT. - - 3. For connections that will be able to use large congestion - windows, this modification eliminates up to three RTTs and a - delayed ACK timeout during the initial slow-start phase. This - will be of particular benefit for high-bandwidth large- - propagation-delay TCP connections, such as those over satellite - links. - -4. Disadvantages of Larger Initial Windows for the Individual - Connection - - In high-congestion environments, particularly for routers that have a - bias against bursty traffic (as in the typical Drop Tail router - queues), a TCP connection can sometimes be better off starting with - an initial window of one segment. There are scenarios where a TCP - connection slow-starting from an initial window of one segment might - not have segments dropped, while a TCP connection starting with an - initial window of four segments might experience unnecessary - retransmits due to the inability of the router to handle small - bursts. This could result in an unnecessary retransmit timeout. For - a large-window connection that is able to recover without a - retransmit timeout, this could result in an unnecessarily-early - transition from the slow-start to the congestion-avoidance phase of - the window increase algorithm. These premature segment drops are - unlikely to occur in uncongested networks with sufficient buffering - or in moderately-congested networks where the congested router uses - active queue management (such as Random Early Detection [FJ93, - RFC2309]). - - Some TCP connections will receive better performance with the larger - initial window even if the burstiness of the initial window results - in premature segment drops. This will be true if (1) the TCP - connection recovers from the segment drop without a retransmit - timeout, and (2) the TCP connection is ultimately limited to a small - congestion window by either network congestion or by the receiver's - advertised window. - -5. Disadvantages of Larger Initial Windows for the Network - - In terms of the potential for congestion collapse, we consider two - separate potential dangers for the network. The first danger would - be a scenario where a large number of segments on congested links - - - -Allman, et. al. Standards Track [Page 4] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - were duplicate segments that had already been received at the - receiver. The second danger would be a scenario where a large number - of segments on congested links were segments that would be dropped - later in the network before reaching their final destination. - - In terms of the negative effect on other traffic in the network, a - potential disadvantage of larger initial windows would be that they - increase the general packet drop rate in the network. We discuss - these three issues below. - - Duplicate segments: - - As described in the previous section, the larger initial window - could occasionally result in a segment dropped from the initial - window, when that segment might not have been dropped if the - sender had slow-started from an initial window of one segment. - However, Appendix A shows that even in this case, the larger - initial window would not result in the transmission of a large - number of duplicate segments. - - Segments dropped later in the network: - - How much would the larger initial window for TCP increase the - number of segments on congested links that would be dropped - before reaching their final destination? This is a problem that - can only occur for connections with multiple congested links, - where some segments might use scarce bandwidth on the first - congested link along the path, only to be dropped later along the - path. - - First, many of the TCP connections will have only one congested - link along the path. Segments dropped from these connections do - not "waste" scarce bandwidth, and do not contribute to congestion - collapse. - - However, some network paths will have multiple congested links, - and segments dropped from the initial window could use scarce - bandwidth along the earlier congested links before ultimately - being dropped on subsequent congested links. To the extent that - the drop rate is independent of the initial window used by TCP - segments, the problem of congested links carrying segments that - will be dropped before reaching their destination will be similar - for TCP connections that start by sending four segments or one - segment. - - - - - - - -Allman, et. al. Standards Track [Page 5] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - An increased packet drop rate: - - For a network with a high segment drop rate, increasing the TCP - initial window could increase the segment drop rate even further. - This is in part because routers with Drop Tail queue management - have difficulties with bursty traffic in times of congestion. - However, given uncorrelated arrivals for TCP connections, the - larger TCP initial window should not significantly increase the - segment drop rate. Simulation-based explorations of these issues - are discussed in Section 7.2. - - These potential dangers for the network are explored in simulations - and experiments described in the section below. Our judgment is that - while there are dangers of congestion collapse in the current - Internet (see [FF99] for a discussion of the dangers of congestion - collapse from an increased deployment of UDP connections without - end-to-end congestion control), there is no such danger to the - network from increasing the TCP initial window to 4K bytes. - -6. Interactions with the Retransmission Timer - - Using a larger initial burst of data can exacerbate existing problems - with spurious retransmit timeouts on low-bandwidth paths, assuming - the standard algorithm for determining the TCP retransmission timeout - (RTO) [RFC2988]. The problem is that across low-bandwidth network - paths on which the transmission time of a packet is a large portion - of the round-trip time, the small packets used to establish a TCP - connection do not seed the RTO estimator appropriately. When the - first window of data packets is transmitted, the sender's retransmit - timer could expire before the acknowledgments for those packets are - received. As each acknowledgment arrives, the retransmit timer is - generally reset. Thus, the retransmit timer will not expire as long - as an acknowledgment arrives at least once a second, given the one- - second minimum on the RTO recommended in RFC 2988. - - For instance, consider a 9.6 Kbps link. The initial RTT measurement - will be on the order of 67 msec, if we simply consider the - transmission time of 2 packets (the SYN and SYN-ACK), each consisting - of 40 bytes. Using the RTO estimator given in [RFC2988], this yields - an initial RTO of 201 msec (67 + 4*(67/2)). However, we round the - RTO to 1 second as specified in RFC 2988. Then assume we send an - initial window of one or more 1500-byte packets (1460 data bytes plus - overhead). Each packet will take on the order of 1.25 seconds to - transmit. Therefore, the RTO will fire before the ACK for the first - packet returns, causing a spurious timeout. In this case, a larger - initial window of three or four packets exacerbates the problems - caused by this spurious timeout. - - - - -Allman, et. al. Standards Track [Page 6] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - One way to deal with this problem is to make the RTO algorithm more - conservative. During the initial window of data, for instance, the - RTO could be updated for each acknowledgment received. In addition, - if the retransmit timer expires for some packet lost in the first - window of data, we could leave the exponential-backoff of the - retransmit timer engaged until at least one valid RTT measurement, - that involves a data packet, is received. - - Another method would be to refrain from taking an RTT sample during - connection establishment, leaving the default RTO in place until TCP - takes a sample from a data segment and the corresponding ACK. While - this method likely helps prevent spurious retransmits, it also may - slow the data transfer down if loss occurs before the RTO is seeded. - The use of limited transmit [RFC3042] to aid a TCP connection in - recovering from loss using fast retransmit rather than the RTO timer - mitigates the performance degradation caused by using the high - default RTO during the initial window of data transmission. - - This specification leaves the decision about what to do (if anything) - with regards to the RTO, when using a larger initial window, to the - implementer. However, the RECOMMENDED approach is to refrain from - sampling the RTT during the three-way handshake, keeping the default - RTO in place until an RTT sample involving a data packet is taken. - In addition, it is RECOMMENDED that TCPs use limited transmit - [RFC3042]. - -7. Typical Levels of Burstiness for TCP Traffic. - - Larger TCP initial windows would not dramatically increase the - burstiness of TCP traffic in the Internet today, because such traffic - is already fairly bursty. Bursts of two and three segments are - already typical of TCP [Flo97]; a delayed ACK (covering two - previously unacknowledged segments) received during congestion - avoidance causes the congestion window to slide and two segments to - be sent. The same delayed ACK received during slow start causes the - window to slide by two segments and then be incremented by one - segment, resulting in a three-segment burst. While not necessarily - typical, bursts of four and five segments for TCP are not rare. - Assuming delayed ACKs, a single dropped ACK causes the subsequent ACK - to cover four previously unacknowledged segments. During congestion - avoidance this leads to a four-segment burst, and during slow start a - five-segment burst is generated. - - There are also changes in progress that reduce the performance - problems posed by moderate traffic bursts. One such change is the - deployment of higher-speed links in some parts of the network, where - a burst of 4K bytes can represent a small quantity of data. A second - change, for routers with sufficient buffering, is the deployment of - - - -Allman, et. al. Standards Track [Page 7] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - queue management mechanisms such as RED, which is designed to be - tolerant of transient traffic bursts. - -8. Simulations and Experimental Results - -8.1 Studies of TCP Connections using that Larger Initial Window - - This section surveys simulations and experiments that explore the - effect of larger initial windows on TCP connections. The first set - of experiments explores performance over satellite links. Larger - initial windows have been shown to improve the performance of TCP - connections over satellite channels [All97b]. In this study, an - initial window of four segments (512 byte MSS) resulted in throughput - improvements of up to 30% (depending upon transfer size). [KAGT98] - shows that the use of larger initial windows results in a decrease in - transfer time in HTTP tests over the ACTS satellite system. A study - involving simulations of a large number of HTTP transactions over - hybrid fiber coax (HFC) indicates that the use of larger initial - windows decreases the time required to load WWW pages [Nic98]. - - A second set of experiments explored TCP performance over dialup - modem links. In experiments over a 28.8 bps dialup channel [All97a, - AHO98], a four-segment initial window decreased the transfer time of - a 16KB file by roughly 10%, with no accompanying increase in the drop - rate. A simulation study [RFC2416] investigated the effects of using - a larger initial window on a host connected by a slow modem link and - a router with a 3 packet buffer. The study concluded that for the - scenario investigated, the use of larger initial windows was not - harmful to TCP performance. - - Finally, [All00] illustrates that the percentage of connections at a - particular web server that experience loss in the initial window of - data transmission increases with the size of the initial congestion - window. However, the increase is in line with what would be expected - from sending a larger burst into the network. - -8.2 Studies of Networks using Larger Initial Windows - - This section surveys simulations and experiments investigating the - impact of the larger window on other TCP connections sharing the - path. Experiments in [All97a, AHO98] show that for 16 KB transfers - to 100 Internet hosts, four-segment initial windows resulted in a - small increase in the drop rate of 0.04 segments/transfer. While the - drop rate increased slightly, the transfer time was reduced by - roughly 25% for transfers using the four-segment (512 byte MSS) - initial window when compared to an initial window of one segment. - - - - - -Allman, et. al. Standards Track [Page 8] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - A simulation study in [RFC2415] explores the impact of a larger - initial window on competing network traffic. In this investigation, - HTTP and FTP flows share a single congested gateway (where the number - of HTTP and FTP flows varies from one simulation set to another). - For each simulation set, the paper examines aggregate link - utilization and packet drop rates, median web page delay, and network - power for the FTP transfers. The larger initial window generally - resulted in increased throughput, slightly-increased packet drop - rates, and an increase in overall network power. With the exception - of one scenario, the larger initial window resulted in an increase in - the drop rate of less than 1% above the loss rate experienced when - using a one-segment initial window; in this scenario, the drop rate - increased from 3.5% with one-segment initial windows, to 4.5% with - four-segment initial windows. The overall conclusions were that - increasing the TCP initial window to three packets (or 4380 bytes) - helps to improve perceived performance. - - Morris [Mor97] investigated larger initial windows in a highly - congested network with transfers of 20K in size. The loss rate in - networks where all TCP connections use an initial window of four - segments is shown to be 1-2% greater than in a network where all - connections use an initial window of one segment. This relationship - held in scenarios where the loss rates with one-segment initial - windows ranged from 1% to 11%. In addition, in networks where - connections used an initial window of four segments, TCP connections - spent more time waiting for the retransmit timer (RTO) to expire to - resend a segment than was spent using an initial window of one - segment. The time spent waiting for the RTO timer to expire - represents idle time when no useful work was being accomplished for - that connection. These results show that in a very congested - environment, where each connection's share of the bottleneck - bandwidth is close to one segment, using a larger initial window can - cause a perceptible increase in both loss rates and retransmit - timeouts. - -9. Security Considerations - - This document discusses the initial congestion window permitted for - TCP connections. Changing this value does not raise any known new - security issues with TCP. - -10. Conclusion - - This document specifies a small change to TCP that will likely be - beneficial to short-lived TCP connections and those over links with - long RTTs (saving several RTTs during the initial slow-start phase). - - - - - -Allman, et. al. Standards Track [Page 9] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - -11. Acknowledgments - - We would like to acknowledge Vern Paxson, Tim Shepard, members of the - End-to-End-Interest Mailing List, and members of the IETF TCP - Implementation Working Group for continuing discussions of these - issues and for feedback on this document. - -12. References - - [AHO98] Mark Allman, Chris Hayes, and Shawn Ostermann, An - Evaluation of TCP with Larger Initial Windows, March 1998. - ACM Computer Communication Review, 28(3), July 1998. URL - "http://roland.lerc.nasa.gov/~mallman/papers/initwin.ps". - - [All97a] Mark Allman. An Evaluation of TCP with Larger Initial - Windows. 40th IETF Meeting -- TCP Implementations WG. - December, 1997. Washington, DC. - - [All97b] Mark Allman. Improving TCP Performance Over Satellite - Channels. Master's thesis, Ohio University, June 1997. - - [All00] Mark Allman. A Web Server's View of the Transport Layer. - ACM Computer Communication Review, 30(5), October 2000. - - [FF96] Fall, K., and Floyd, S., Simulation-based Comparisons of - Tahoe, Reno, and SACK TCP. Computer Communication Review, - 26(3), July 1996. - - [FF99] Sally Floyd, Kevin Fall. Promoting the Use of End-to-End - Congestion Control in the Internet. IEEE/ACM Transactions - on Networking, August 1999. URL - "http://www.icir.org/floyd/end2end-paper.html". - - [FJ93] Floyd, S., and Jacobson, V., Random Early Detection - gateways for Congestion Avoidance. IEEE/ACM Transactions on - Networking, V.1 N.4, August 1993, p. 397-413. - - [Flo94] Floyd, S., TCP and Explicit Congestion Notification. - Computer Communication Review, 24(5):10-23, October 1994. - - [Flo96] Floyd, S., Issues of TCP with SACK. Technical report, - January 1996. Available from http://www- - nrg.ee.lbl.gov/floyd/. - - [Flo97] Floyd, S., Increasing TCP's Initial Window. Viewgraphs, - 40th IETF Meeting - TCP Implementations WG. December, 1997. - URL "ftp://ftp.ee.lbl.gov/talks/sf-tcp-ietf97.ps". - - - - -Allman, et. al. Standards Track [Page 10] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - [KAGT98] Hans Kruse, Mark Allman, Jim Griner, Diepchi Tran. HTTP - Page Transfer Rates Over Geo-Stationary Satellite Links. - March 1998. Proceedings of the Sixth International - Conference on Telecommunication Systems. URL - "http://roland.lerc.nasa.gov/~mallman/papers/nash98.ps". - - [Mor97] Robert Morris. Private communication, 1997. Cited for - acknowledgement purposes only. - - [Nic98] Kathleen Nichols. Improving Network Simulation With - Feedback, Proceedings of LCN 98, October 1998. URL - "http://www.computer.org/proceedings/lcn/8810/8810toc.htm". - - [Pos82] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC - 821, August 1982. - - [RFC1122] Braden, R., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC1191] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191, - November 1990. - - [RFC1945] Berners-Lee, T., Fielding, R. and H. Nielsen, "Hypertext - Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996. - - [RFC2068] Fielding, R., Mogul, J., Gettys, J., Frystyk, H. and T. - Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC - 2616, January 1997. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2309] Braden, B., Clark, D., Crowcroft, J., Davie, B., Deering, - S., Estrin, D., Floyd, S., Jacobson, V., Minshall, G., - Partridge, C., Peterson, L., Ramakrishnan, K., Shenker, S., - Wroclawski, J. and L. Zhang, "Recommendations on Queue - Management and Congestion Avoidance in the Internet", RFC - 2309, April 1998. - - [RFC2414] Allman, M., Floyd, S. and C. Partridge, "Increasing TCP's - Initial Window", RFC 2414, September 1998. - - [RFC2415] Poduri, K. and K. Nichols, "Simulation Studies of Increased - Initial TCP Window Size", RFC 2415, September 1998. - - [RFC2416] Shepard, T. and C. Partridge, "When TCP Starts Up With Four - Packets Into Only Three Buffers", RFC 2416, September 1998. - - - - -Allman, et. al. Standards Track [Page 11] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2821] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, - April 2001. - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [RFC3042] Allman, M., Balakrishnan, H. and S. Floyd, "Enhancing TCP's - Loss Recovery Using Limited Transmit", RFC 3042, January - 2001. - - [RFC3168] Ramakrishnan, K.K., Floyd, S. and D. Black, "The Addition - of Explicit Congestion Notification (ECN) to IP", RFC 3168, - September 2001. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Allman, et. al. Standards Track [Page 12] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - -Appendix A - Duplicate Segments - - In the current environment (without Explicit Congestion Notification - [Flo94] [RFC2481]), all TCPs use segment drops as indications from - the network about the limits of available bandwidth. We argue here - that the change to a larger initial window should not result in the - sender retransmitting a large number of duplicate segments that have - already arrived at the receiver. - - If one segment is dropped from the initial window, there are three - different ways for TCP to recover: (1) Slow-starting from a window of - one segment, as is done after a retransmit timeout, or after Fast - Retransmit in Tahoe TCP; (2) Fast Recovery without selective - acknowledgments (SACK), as is done after three duplicate ACKs in Reno - TCP; and (3) Fast Recovery with SACK, for TCP where both the sender - and the receiver support the SACK option [MMFR96]. In all three - cases, if a single segment is dropped from the initial window, no - duplicate segments (i.e., segments that have already been received at - the receiver) are transmitted. Note that for a TCP sending four - 512-byte segments in the initial window, a single segment drop will - not require a retransmit timeout, but can be recovered by using the - Fast Retransmit algorithm (unless the retransmit timer expires - prematurely). In addition, a single segment dropped from an initial - window of three segments might be repaired using the fast retransmit - algorithm, depending on which segment is dropped and whether or not - delayed ACKs are used. For example, dropping the first segment of a - three segment initial window will always require waiting for a - timeout, in the absence of Limited Transmit [RFC3042]. However, - dropping the third segment will always allow recovery via the fast - retransmit algorithm, as long as no ACKs are lost. - - Next we consider scenarios where the initial window contains two to - four segments, and at least two of those segments are dropped. If - all segments in the initial window are dropped, then clearly no - duplicate segments are retransmitted, as the receiver has not yet - received any segments. (It is still a possibility that these dropped - segments used scarce bandwidth on the way to their drop point; this - issue was discussed in Section 5.) - - When two segments are dropped from an initial window of three - segments, the sender will only send a duplicate segment if the first - two of the three segments were dropped, and the sender does not - receive a packet with the SACK option acknowledging the third - segment. - - When two segments are dropped from an initial window of four - segments, an examination of the six possible scenarios (which we - don't go through here) shows that, depending on the position of the - - - -Allman, et. al. Standards Track [Page 13] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - - dropped packets, in the absence of SACK the sender might send one - duplicate segment. There are no scenarios in which the sender sends - two duplicate segments. - - When three segments are dropped from an initial window of four - segments, then, in the absence of SACK, it is possible that one - duplicate segment will be sent, depending on the position of the - dropped segments. - - The summary is that in the absence of SACK, there are some scenarios - with multiple segment drops from the initial window where one - duplicate segment will be transmitted. There are no scenarios in - which more than one duplicate segment will be transmitted. Our - conclusion is than the number of duplicate segments transmitted as a - result of a larger initial window should be small. - -Author's Addresses - - Mark Allman - BBN Technologies/NASA Glenn Research Center - 21000 Brookpark Rd - MS 54-5 - Cleveland, OH 44135 - EMail: mallman@bbn.com - http://roland.lerc.nasa.gov/~mallman/ - - Sally Floyd - ICSI Center for Internet Research - 1947 Center St, Suite 600 - Berkeley, CA 94704 - Phone: +1 (510) 666-2989 - EMail: floyd@icir.org - http://www.icir.org/floyd/ - - Craig Partridge - BBN Technologies - 10 Moulton St - Cambridge, MA 02138 - EMail: craig@bbn.com - - - - - - - - - - - - -Allman, et. al. Standards Track [Page 14] - -RFC 3390 Increasing TCP's Initial Window October 2002 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Allman, et. al. Standards Track [Page 15] - diff --git a/ext/picotcp/RFC/rfc3465.txt b/ext/picotcp/RFC/rfc3465.txt deleted file mode 100644 index 32b38c3..0000000 --- a/ext/picotcp/RFC/rfc3465.txt +++ /dev/null @@ -1,563 +0,0 @@ - - - - - - -Network Working Group M. Allman -Request for Comments: 3465 BBN/NASA GRC -Category: Experimental February 2003 - - - TCP Congestion Control with Appropriate Byte Counting (ABC) - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - This document proposes a small modification to the way TCP increases - its congestion window. Rather than the traditional method of - increasing the congestion window by a constant amount for each - arriving acknowledgment, the document suggests basing the increase on - the number of previously unacknowledged bytes each ACK covers. This - change improves the performance of TCP, as well as closes a security - hole TCP receivers can use to induce the sender into increasing the - sending rate too rapidly. - -Terminology - - Much of the language in this document is taken from [RFC2581]. - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in [RFC2119]. - -1 Introduction - - This document proposes a modification to the algorithm for increasing - TCP's congestion window (cwnd) that improves both performance and - security. Rather than increasing a TCP's congestion window based on - the number of acknowledgments (ACKs) that arrive at the data sender - (per the current specification [RFC2581]), the congestion window is - increased based on the number of bytes acknowledged by the arriving - ACKs. The algorithm improves performance by mitigating the impact of - delayed ACKs on the growth of cwnd. At the same time, the algorithm - provides cwnd growth in direct relation to the probed capacity of a - - - -Allman Experimental [Page 1] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - - network path, therefore providing a more measured response to ACKs - that cover only small amounts of data (less than a full segment size) - than ACK counting. This more appropriate cwnd growth can improve - both performance and can prevent inappropriate cwnd growth in - response to a misbehaving receiver. On the other hand, in some cases - the modified cwnd growth algorithm causes larger bursts of segments - to be sent into the network. In some cases this can lead to a non- - negligible increase in the drop rate and reduced performance (see - section 4 for a larger discussion of the issues). - - This document is organized as follows. Section 2 outlines the - modified algorithm for increasing TCP's congestion window. Section 3 - discusses the advantages of using the modified algorithm. Section 4 - discusses the disadvantages of the approach outlined in this - document. Section 5 outlines some of the fairness issues that must - be considered for the modified algorithm. Section 6 discusses - security considerations. - - Statement of Intent - - This specification contains an algorithm improving the performance - of TCP which is understood to be effective and safe, but which has - not been widely deployed. One goal of publication as an - Experimental RFC is to be prudent, and encourage use and - deployment prior to publication in the standards track. It is the - intent of the Transport Area to re-submit this specification as an - IETF Proposed Standard in the future, after more experience has - been gained. - -2 A Modified Algorithm for Increasing the Congestion Window - - As originally outlined in [Jac88] and specified in [RFC2581], TCP - uses two algorithms for increasing the congestion window. During - steady-state, TCP uses the Congestion Avoidance algorithm to linearly - increase the value of cwnd. At the beginning of a transfer, after a - retransmission timeout or after a long idle period (in some - implementations), TCP uses the Slow Start algorithm to increase cwnd - exponentially. According to RFC 2581, slow start bases the cwnd - increase on the number of incoming acknowledgments. During - congestion avoidance RFC 2581 allows more latitude in increasing - cwnd, but traditionally implementations have based the increase on - the number of arriving ACKs. In the following two subsections, we - detail modifications to these algorithms to increase cwnd based on - the number of bytes being acknowledged by each arriving ACK, rather - than by the number of ACKs that arrive. We call these changes - "Appropriate Byte Counting" (ABC) [All99]. - - - - - -Allman Experimental [Page 2] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - -2.1 Congestion Avoidance - - RFC 2581 specifies that cwnd should be increased by 1 segment per - round-trip time (RTT) during the congestion avoidance phase of a - transfer. Traditionally, TCPs have approximated this increase by - increasing cwnd by 1/cwnd for each arriving ACK. This algorithm - opens cwnd by roughly 1 segment per RTT if the receiver ACKs each - incoming segment and no ACK loss occurs. However, if the receiver - implements delayed ACKs [Bra89], the receiver returns roughly half as - many ACKs, which causes the sender to open cwnd more conservatively - (by approximately 1 segment every second RTT). The approach that - this document suggests is to store the number of bytes that have been - ACKed in a "bytes_acked" variable in the TCP control block. When - bytes_acked becomes greater than or equal to the value of the - congestion window, bytes_acked is reduced by the value of cwnd. - Next, cwnd is incremented by a full-sized segment (SMSS). The - algorithm suggested above is specifically allowed by RFC 2581 during - congestion avoidance because it opens the window by at most 1 segment - per RTT. - -2.2 Slow Start - - RFC 2581 states that the sender increments the congestion window by - at most, 1*SMSS bytes for each arriving acknowledgment during slow - start. This document proposes that a TCP sender SHOULD increase cwnd - by the number of previously unacknowledged bytes ACKed by each - incoming acknowledgment, provided the increase is not more than L - bytes. Choosing the limit on the increase, L, is discussed in the - next subsection. When the number of previously unacknowledged bytes - ACKed is less than or equal to 1*SMSS bytes, or L is less than or - equal to 1*SMSS bytes, this proposal is no more aggressive (and - possibly less aggressive) than allowed by RFC 2581. However, - increasing cwnd by more than 1*SMSS bytes in response to a single ACK - is more aggressive than allowed by RFC 2581. The more aggressive - version of the slow start algorithm still falls within the spirit of - the principles outlined in [Jac88] (i.e., of no more than doubling - the cwnd per RTT), and this document proposes ABC for experimentation - in shared networks, provided an appropriate limit is applied (see - next section). - -2.3 Choosing the Limit - - The limit, L, chosen for the cwnd increase during slow start, - controls the aggressiveness of the algorithm. Choosing L=1*SMSS - bytes provides behavior that is no more aggressive than allowed by - RFC 2581. However, ABC with L=1*SMSS bytes is more conservative in a - - - - - -Allman Experimental [Page 3] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - - number of key ways (as discussed in the next section) and therefore, - this document suggests that even though with L=1*SMSS bytes TCP - stacks will see little performance change, ABC SHOULD be used. - - A very large L could potentially lead to large line-rate bursts of - traffic in the face of a large amount of ACK loss or in the case when - the receiver sends "stretch ACKs" (ACKs for more than the two full- - sized segments allowed by the delayed ACK algorithm) [Pax97]. - - This document specifies that TCP implementations MAY use L=2*SMSS - bytes and MUST NOT use L > 2*SMSS bytes. This choice balances - between being conservative (L=1*SMSS bytes) and being potentially - very aggressive. In addition, L=2*SMSS bytes exactly balances the - negative impact of the delayed ACK algorithm (as discussed in more - detail in section 3.2). Note that when L=2*SMSS bytes cwnd growth is - roughly the same as the case when the standard algorithms are used in - conjunction with a receiver that transmits an ACK for each incoming - segment [All98] (assuming no or small amounts of ACK loss in both - cases). - - The exception to the above suggestion is during a slow start phase - that follows a retransmission timeout (RTO). In this situation, a - TCP MUST use L=1*SMSS as specified in RFC 2581 since ACKs for large - amounts of previously unacknowledged data are common during this - phase of a transfer. These ACKs do not necessarily indicate how much - data has left the network in the last RTT, and therefore ABC cannot - accurately determine how much to increase cwnd. As an example, say - segment N is dropped by the network, and segments N+1 and N+2 arrive - successfully at the receiver. The sender will receive only two - duplicate ACKs and therefore must rely on the retransmission timer - (RTO) to detect the loss. When the RTO expires, segment N is - retransmitted. The ACK sent in response to the retransmission will - be for segment N+2. However, this ACK does not indicate that three - segments have left the network in the last RTT, but rather only a - single segment left the network. Therefore, the appropriate cwnd - increment is at most 1*SMSS bytes. - -2.4 RTO Implications - - [Jac88] shows that increases in cwnd of more than a factor of two in - succeeding RTTs can cause spurious retransmissions on slow links - where the bandwidth dominates the RTT, assuming the RTO estimator - given in [Jac88] and [RFC2988]. ABC stays within this limit of no - more than doubling cwnd in successive RTTs by capping the increase - (no matter what L is employed) by the number of previously - unacknowledged bytes covered by each incoming ACK. - - - - - -Allman Experimental [Page 4] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - -3 Advantages - - This section outlines several advantages of using the ABC algorithm - to increase cwnd, rather than the standard ACK counting algorithm - given in [RFC2581]. - -3.1 More Appropriate Congestion Window Increase - - The ABC algorithm outlined in section 2 increases TCP's cwnd in - proportion to the amount of data actually sent into the network. ACK - counting, on the other hand, increments cwnd by a constant upon the - arrival of each ACK. For instance, consider an interactive telnet - connection (e.g., ssh or telnet) in which ACKs generally cover only a - few bytes of data, but cwnd is increased by 1*SMSS bytes for each ACK - received. When a large amount of data needs to be transmitted (e.g., - displaying a large file) the data is sent in one large burst because - the cwnd grows by 1*SMSS bytes per ACK rather than based on the - actual amount of capacity used. Such a line-rate burst of data can - potentially cause a large amount of segment loss. - - Congestion Window Validation (CWV) [RFC2861] addresses the above - problem as well. CWV limits the amount of unused cwnd a TCP - connection can accumulate. ABC can be used in conjunction with CWV - to obtain an accurate measure of the network path. - -3.2 Mitigate the Impact of Delayed ACKs and Lost ACKs - - Delayed ACKs [RFC1122,RFC2581] allow a TCP receiver to refrain from - sending an ACK for each incoming segment. However, a receiver SHOULD - send an ACK for every second full-sized segment that arrives. - Furthermore, a receiver MUST NOT withhold an ACK for more than 500 - ms. By reducing the number of ACKs sent to the data originator the - receiver is slowing the growth of the congestion window under an ACK - counting system. Using ABC with L=2*SMSS bytes can roughly negate - the negative impact imposed by delayed ACKs by allowing cwnd to be - increased for ACKs that are withheld by the receiver. This allows - the congestion window to grow in a manner similar to the case when - the receiver ACKs each incoming segment, but without adding extra - traffic to the network. Simulation studies have shown increased - throughput when a TCP sender uses ABC when compared to the standard - ACK counting algorithm [All99], especially for short transfers that - never leave the initial slow start period. - - Note that delayed ACKs should not be an issue during slow start-based - loss recovery, as RFC 2581 recommends that receivers should not delay - ACKs that cover out-of-order segments. Therefore, as discussed - above, ABC with L > 1*SMSS bytes is inappropriate for such slow start - based loss recovery and MUST NOT be used. - - - -Allman Experimental [Page 5] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - - Note: In the case when an entire window of data is lost, a TCP - receiver will likely generate delayed ACKs and an L > 1*SMSS bytes - would be safe. However, detecting this scenario is difficult. - Therefore to keep ABC conservative, this document mandates that L - MUST NOT be > 1*SMSS bytes in any slow start-based loss recovery. - - ACK loss can also retard the growth of a congestion window that - increases based on the number of ACKs that arrive. When counting - ACKs, dropped ACKs represent forever-missed opportunities to increase - cwnd. Using ABC with L > 1*SMSS bytes allows the sender to mitigate - the effect of lost ACKs. - -3.3 Prevents Attacks from Misbehaving Receivers - - [SCWA99] outlines several methods for a receiver to induce a TCP - sender into violating congestion control and transmitting data at a - potentially inappropriate rate. One of the outlined attacks is "ACK - Division". This scheme involves the receiver sending multiple ACKs - for each incoming data segment, each ACKing only a small portion of - the original TCP data segment. Since TCP senders have traditionally - used ACK counting to increase cwnd, ACK division causes - inappropriately rapid cwnd growth and, in turn, a potentially - inappropriate sending rate. A TCP sender that uses ABC can prevent - this attack from being used to undermine standard congestion control - because the cwnd increase is based on the number of bytes ACKed, - rather than the number of ACKs received. - - To prevent misbehaving receivers from inducing inappropriate sender - behavior, this document suggests TCP implementations use ABC, even if - L=1*SMSS bytes (i.e., not allowing ABC to provide more aggressive - cwnd growth than allowed by RFC 2581). - -4 Disadvantages - - The main disadvantages of using ABC with L=2*SMSS bytes are an - increase in the burstiness of TCP and a small increase in the overall - loss rate. [All98] discusses the two ways that ABC increases the - burstiness of the TCP sender. First, the "micro burstiness" of the - connection is increased. In other words, the number of segments sent - in response to each incoming ACK is increased by at most 1 segment - when using ABC with L=2*SMSS bytes in conjunction with a receiver - that is sending delayed ACKs. During slow start this translates into - an increase from sending 2 back-to-back segments to sending 3 back- - to-back packets in response to an ACK for a single packet. Or, an - increase from 3 packets to 4 packets when receiving a delayed ACK for - two outstanding packets. Note that ACK loss can cause larger bursts. - However, ABC only increases the burst size by at most 1*SMSS bytes - per ACK received when compared to the standard behavior. This slight - - - -Allman Experimental [Page 6] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - - increase in the burstiness should only cause problems for devices - that have very small buffers. In addition, ABC increases the "macro - burstiness" of the TCP sender in response to delayed ACKs in slow - start. Rather than increasing cwnd by roughly 1.5 times per RTT, ABC - roughly doubles the congestion window every RTT. However, doubling - cwnd every RTT fits within the spirit of slow start, as originally - outlined [Jac88]. - - With the increased burstiness comes a modest increase in the loss - rate for a TCP connection employing ABC (see the next section for a - short discussion on the fairness of ABC to non-ABC flows). The - additional loss can be directly attributable to the increased - aggressiveness of ABC. During slow start cwnd is increased more - rapidly. Therefore when loss occurs cwnd is larger and more drops - are likely. Similarly, a congestion avoidance cycle takes roughly - half, as long when using ABC and delayed ACKs when compared to an ACK - counting implementation. In other words, a TCP sender reaches the - capacity of the network path, drops a packet and reduces the - congestion window by half roughly twice as often when using ABC. - However, as discussed above, in spite of the additional loss an ABC - TCP sender generally obtains better overall performance than a non- - ABC TCP [All99]. - - Due to the increase in the packet drop rate we suggest ABC be - implemented in conjunction with selective acknowledgments [RFC2018]. - -5 Fairness Considerations - - [All99] presents several simple simulations conducted to measure the - impact of ABC on competing traffic (both ABC and non-ABC). The - experiments show that while ABC increases the drop rate for the - connection using ABC, competing traffic is not greatly effected. The - experiments show that standard TCP and ABC both obtain roughly the - same throughput, regardless of the variant of the competing traffic. - The simulations also reaffirm that ABC outperforms non-ABC TCP in an - environment with varying types of TCP connections. On the other - hand, the simulations presented in [All99] are not necessarily - realistic. Therefore we are encouraging more experimentation in the - Internet. - -6 Security Considerations - - As discussed in section 3.3, ABC protects a TCP sender from a - misbehaving receiver that induces the sender into transmitting at an - inappropriate rate with an "ACK division" attack. This, in turn, - protects the network from an overly aggressive sender. - - - - - -Allman Experimental [Page 7] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - -7 Conclusions - - This document RECOMMENDS that all TCP stacks be modified to use ABC - with L=1*SMSS bytes. This change does not increase the - aggressiveness of TCP. Furthermore, simulations of ABC with L=2*SMSS - bytes show a promising performance improvement that we encourage - researchers to experiment with in the Internet. - -Acknowledgments - - This document has benefited from discussions with and encouragement - from Sally Floyd. Van Jacobson and Reiner Ludwig provided valuable - input on the implications of byte counting on the RTO. Reiner Ludwig - and Kostas Pentikousis provided valuable feedback on a draft of this - document. - -Normative References - - [RFC1122] Braden, R., Ed., "Requirements for Internet Hosts -- - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - -Informative References - - [All98] Mark Allman. On the Generation and Use of TCP - Acknowledgments. ACM Computer Communication Review, 29(3), - July 1998. - - [All99] Mark Allman. TCP Byte Counting Refinements. ACM Computer - Communication Review, 29(3), July 1999. - - [Jac88] Van Jacobson. Congestion Avoidance and Control. ACM - SIGCOMM 1988. - - [Pax97] Vern Paxson. Automated Packet Trace Analysis of TCP - Implementations. ACM SIGCOMM, September 1997. - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgment Options", RFC 2018, October 1996. - - [RFC2861] Handley, M., Padhye, J. and S. Floyd, "TCP Congestion - Window Validation", RFC 2861, June 2000. - - - - -Allman Experimental [Page 8] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - - [SCWA99] Stefan Savage, Neal Cardwell, David Wetherall, Tom - Anderson. TCP Congestion Control with a Misbehaving - Receiver. ACM Computer Communication Review, 29(5), - October 1999. - -Author's Address - - Mark Allman - BBN Technologies/NASA Glenn Research Center - Lewis Field - 21000 Brookpark Rd. MS 54-5 - Cleveland, OH 44135 - - Fax: 216-433-8705 - Phone: 216-433-6586 - EMail: mallman@bbn.com - http://roland.grc.nasa.gov/~mallman - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Allman Experimental [Page 9] - -RFC 3465 TCP Congestion Control with ABC February 2003 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Allman Experimental [Page 10] - diff --git a/ext/picotcp/RFC/rfc3481.txt b/ext/picotcp/RFC/rfc3481.txt deleted file mode 100644 index 6c45efe..0000000 --- a/ext/picotcp/RFC/rfc3481.txt +++ /dev/null @@ -1,1459 +0,0 @@ - - - - - - -Network Working Group H. Inamura, Ed. -Request for Comments: 3481 NTT DoCoMo, Inc. -BCP: 71 G. Montenegro, Ed. -Category: Best Current Practice Sun Microsystems Laboratories - Europe - R. Ludwig - Ericsson Research - A. Gurtov - Sonera - F. Khafizov - Nortel Networks - February 2003 - - - TCP over Second (2.5G) and Third (3G) Generation Wireless Networks - -Status of this Memo - - This document specifies an Internet Best Current Practices for the - Internet Community, and requests discussion and suggestions for - improvements. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - This document describes a profile for optimizing TCP to adapt so that - it handles paths including second (2.5G) and third (3G) generation - wireless networks. It describes the relevant characteristics of 2.5G - and 3G networks, and specific features of example deployments of such - networks. It then recommends TCP algorithm choices for nodes known - to be starting or ending on such paths, and it also discusses open - issues. The configuration options recommended in this document are - commonly found in modern TCP stacks, and are widely available - standards-track mechanisms that the community considers safe for use - on the general Internet. - - - - - - - - - - - - - -Inamura, et al. Best Current Practice [Page 1] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -Table of Contents - - 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. 2.5G and 3G Link Characteristics. . . . . . . . . . . . . . . 4 - 2.1 Latency. . . . . . . . . . . . . . . . . . . . . . . . . 4 - 2.2 Data Rates . . . . . . . . . . . . . . . . . . . . . . . 5 - 2.3 Asymmetry . . . . . . . . . . . . . . . . . . . . . . . 6 - 2.4 Delay Spikes . . . . . . . . . . . . . . . . . . . . . . 6 - 2.5 Packet Loss Due to Corruption. . . . . . . . . . . . . . 7 - 2.6 Intersystem Handovers. . . . . . . . . . . . . . . . . . 7 - 2.7 Bandwidth Oscillation. . . . . . . . . . . . . . . . . . 7 - 3. Example 2.5G and 3G Deployments . . . . . . . . . . . . . . . 8 - 3.1 2.5G Technologies: GPRS, HSCSD and CDMA2000 1XRTT. . . . 8 - 3.2 A 3G Technology: W-CDMA. . . . . . . . . . . . . . . . . 8 - 3.3 A 3G Technology: CDMA2000 1X-EV. . . . . . . . . . . . . 10 - 4. TCP over 2.5G and 3G. . . . . . . . . . . . . . . . . . . . . 10 - 4.1 Appropriate Window Size (Sender & Receiver). . . . . . . 11 - 4.2 Increased Initial Window (Sender). . . . . . . . . . . . 11 - 4.3 Limited Transmit (Sender). . . . . . . . . . . . . . . . 12 - 4.4 IP MTU Larger than Default . . . . . . . . . . . . . . . 12 - 4.5 Path MTU Discovery (Sender & Intermediate Routers) . . . 13 - 4.6 Selective Acknowledgments (Sender & Receiver). . . . . . 13 - 4.7 Explicit Congestion Notification (Sender, Receiver & - Intermediate Routers). . . . . . . . . . . . . . . . . . 13 - 4.8 TCP Timestamps Option (Sender & Receiver). . . . . . . . 13 - 4.9 Disabling RFC 1144 TCP/IP Header Compression (Wireless - Host) . . . . . . . . . . . . . . . . . . . . . . . . . 15 - 4.10 Summary . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 5. Open Issues . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 6. Security Considerations . . . . . . . . . . . . . . . . . . . 18 - 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 18 - 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 19 - 9. Normative References . . . . . . . . . . . . . . . . . . . . . 19 - 10. Informative References . . . . . . . . . . . . . . . . . . . . 21 - 11. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 25 - 12. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 26 - - - - - - - - - - - - - - - -Inamura, et al. Best Current Practice [Page 2] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -1. Introduction - - The second generation cellular systems are commonly referred to as - 2G. The 2G phase began in the 1990s when digital voice encoding had - replaced analog systems (1G). 2G systems are based on various radio - technologies including frequency-, code- and time- division multiple - access. Examples of 2G systems include GSM (Europe), PDC (Japan), - and IS-95 (USA). Data links provided by 2G systems are mostly - circuit-switched and have transmission speeds of 10-20 kbps uplink - and downlink. Demand for higher data rates, instant availability and - data volume-based charging, as well as lack of radio spectrum - allocated for 2G led to the introduction of 2.5G (for example, GPRS - and PDC-P) and 3G (for example, Wideband CDMA and cdma2000) systems. - - Radio technology for both Wideband CDMA (W-CDMA) (adopted, for - example, in Europe, Japan, etc) and cdma2000 (adopted, for example, - in US, South Korea, etc) is based on code division multiple access - allowing for higher data rates and more efficient spectrum - utilization than 2G systems. 3G systems provide both packet-switched - and circuit-switched connectivity in order to address the quality of - service requirements of conversational, interactive, streaming, and - bulk transfer applications. The transition to 3G is expected to be a - gradual process. Initially, 3G will be deployed to introduce high - capacity and high speed access in densely populated areas. Mobile - users with multimode terminals will be able to utilize existing - coverage of 2.5G systems on the rest of territory. - - Much development and deployment activity has centered around 2.5G and - 3G technologies. Along with objectives like increased capacity for - voice channels, a primary motivation for these is data communication, - and, in particular, Internet access. Accordingly, key issues are TCP - performance and the several techniques which can be applied to - optimize it over different wireless environments [19]. - - This document proposes a profile of such techniques, (particularly - effective for use with 2.5G and 3G wireless networks). The - configuration options in this document are commonly found in modern - TCP stacks, and are widely available IETF standards-track mechanisms - that the community has judged to be safe on the general Internet - (that is, even in predominantly non-wireless scenarios). - Furthermore, this document makes one set of recommendations that - covers both 2.5G and 3G networks. Since both generations of wireless - technologies exhibit similar challenges to TCP performance (see - Section 2), one common set is warranted. - - - - - - - -Inamura, et al. Best Current Practice [Page 3] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - Two example applications of the recommendations in this document are: - - o The WAP Forum [25] (part of the Open Mobile Alliance [26] as of - June 2002) is an industry association that has developed standards - for wireless information and telephony services on digital mobile - phones. In order to address WAP functionality for higher speed - networks such as 2.5G and 3G networks, and to aim at convergence - with Internet standards, the WAP Forum thoroughly revised its - specifications. The resultant version 2.0 [31] adopts TCP as its - transport protocol, and recommends TCP optimization mechanisms - closely aligned with those described in this document. - - o I-mode [33] is a wireless Internet service deployed on handsets in - Japan. The newer version of i-mode runs on FOMA [34], an - implementation of W-CDMA. I-mode over FOMA deploys the profile of - TCP described in this document. - - This document is structured as follows: Section 2 reviews the link - layer characteristics of 2.5G/3G networks; Section 3 gives a brief - overview of some representative 2.5G/3G technologies like W-CDMA, - cdma2000 and GPRS; Section 4 recommends mechanisms and configuration - options for TCP implementations used in 2.5G/3G networks, including a - summary in chart form at the end of the section; finally, Section 5 - discusses some open issues. - -2. 2.5G and 3G Link Characteristics - - Link layer characteristics of 2.5G/3G networks have significant - effects on TCP performance. In this section we present various - aspects of link characteristics unique to the 2.5G/3G networks. - -2.1 Latency - - The latency of 2.5G/3G links is high mostly due to the extensive - processing required at the physical layer of those networks, e.g., - for FEC and interleaving, and due to transmission delays in the radio - access network [58] (including link-level retransmissions). A - typical RTT varies between a few hundred milliseconds and one second. - The associated radio channels suffer from difficult propagation - environments. Hence, powerful but complex physical layer techniques - need to be applied to provide high capacity in a wide coverage area - in a resource efficient way. Hopefully, rapid improvements in all - areas of wireless networks ranging from radio layer techniques over - signal processing to system architecture will ultimately also lead to - reduced delays in 3G wireless systems. - - - - - - -Inamura, et al. Best Current Practice [Page 4] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -2.2 Data Rates - - The main incentives for transition from 2G to 2.5G to 3G are the - increase in voice capacity and in data rates for the users. 2.5G - systems have data rates of 10-20 kbps in uplink and 10-40 kbps in - downlink. Initial 3G systems are expected to have bit rates around - 64 kbps in uplink and 384 kbps in downlink. Considering the - resulting bandwidth-delay product (BDP) of around 1-5 KB for 2.5G and - 8-50 KB for 3G, 2.5G links can be considered LTNs (Long Thin Networks - [19]), and 3G links approach LFNs (Long Fat Networks [2], as - exemplified by some satellite networks [48]). Accordingly, - interested readers might find related and potentially relevant issues - discussed in RFC 2488 [49]. For good TCP performance both LFNs and - LTNs require maintaining a large enough window of outstanding data. - For LFNs, utilizing the available network bandwidth is of particular - concern. LTNs need a sufficiently large window for efficient loss - recovery. In particular, the fast retransmit algorithm cannot be - triggered if the window is less than four segments. This leads to a - lengthy recovery through retransmission timeouts. The Limited - Transmit algorithm RFC 3042 [10] helps avoid the deleterious effects - of timeouts on connections with small windows. Nevertheless, making - full use of the SACK RFC 2018 [3] information for loss recovery in - both LFNs and LTNs may require twice the window otherwise sufficient - to utilize the available bandwidth. - - This document recommends only standard mechanisms suitable both for - LTNs and LFNs, and to any network in general. However, experimental - mechanisms suggested in Section 5 can be targeted either for LTNs - [19] or LFNs [48]. - - Data rates are dynamic due to effects from other users and from - mobility. Arriving and departing users can reduce or increase the - available bandwidth in a cell. Increasing the distance from the base - station decreases the link bandwidth due to reduced link quality. - Finally, by simply moving into another cell the user can experience a - sudden change in available bandwidth. For example, if upon changing - cells a connection experiences a sudden increase in available - bandwidth, it can underutilize it, because during congestion - avoidance TCP increases the sending rate slowly. Changing from a - fast to a slow cell normally is handled well by TCP due to the self- - clocking property. However, a sudden increase in RTT in this case - can cause a spurious TCP timeout as described in Section 2.7. In - addition, a large TCP window used in the fast cell can create - congestion resulting in overbuffering in the slow cell. - - - - - - - -Inamura, et al. Best Current Practice [Page 5] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -2.3 Asymmetry - - 2.5G/3G systems may run asymmetric uplink and downlink data rates. - The uplink data rate is limited by battery power consumption and - complexity limitations of mobile terminals. However, the asymmetry - does not exceed 3-6 times, and can be tolerated by TCP without the - need for techniques like ACK congestion control or ACK filtering - [50]. Accordingly, this document does not include recommendations - meant for such highly asymmetric networks. - -2.4 Delay Spikes - - A delay spike is a sudden increase in the latency of the - communication path. 2.5G/3G links are likely to experience delay - spikes exceeding the typical RTT by several times due to the - following reasons. - - 1. A long delay spike can occur during link layer recovery from a - link outage due to temporal loss of radio coverage, for example, - while driving into a tunnel or within an elevator. - - 2. During a handover the mobile terminal and the new base station - must exchange messages and perform some other time-consuming - actions before data can be transmitted in a new cell. - - 3. Many wide area wireless networks provide seamless mobility by - internally re-routing packets from the old to the new base station - which may cause extra delay. - - 4. Blocking by high-priority traffic may occur when an arriving - circuit-switched call or higher priority data temporarily preempts - the radio channel. This happens because most current terminals - are not able to handle a voice call and a data connection - simultaneously and suspend the data connection in this case. - - 5. Additionally, a scheduler in the radio network can suspend a low- - priority data transfer to give the radio channel to higher - priority users. - - Delay spikes can cause spurious TCP timeouts, unnecessary - retransmissions and a multiplicative decrease in the congestion - window size. - - - - - - - - - -Inamura, et al. Best Current Practice [Page 6] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -2.5 Packet Loss Due to Corruption - - Even in the face of a high probability of physical layer frame - errors, 2.5G/3G systems have a low rate of packet losses thanks to - link-level retransmissions. Justification for link layer ARQ is - discussed in [23], [22], [44]. In general, link layer ARQ and FEC - can provide a packet service with a negligibly small probability of - undetected errors (failures of the link CRC), and a low level of loss - (non-delivery) for the upper layer traffic, e.g., IP. The loss rate - of IP packets is low due to the ARQ, but the recovery at the link - layer appears as delay jitter to the higher layers lengthening the - computed RTO value. - -2.6 Intersystem Handovers - - In the initial phase of deployment, 3G systems will be used as a 'hot - spot' technology in high population areas, while 2.5G systems will - provide lower speed data service elsewhere. This creates an - environment where a mobile user can roam between 2.5G and 3G networks - while keeping ongoing TCP connections. The inter-system handover is - likely to trigger a high delay spike (Section 2.4), and can result in - data loss. Additional problems arise because of context transfer, - which is out of scope of this document, but is being addressed - elsewhere in the IETF in activities addressing seamless mobility - [51]. - - Intersystem handovers can adversely affect ongoing TCP connections - since features may only be negotiated at connection establishment and - cannot be changed later. After an intersystem handover, the network - characteristics may be radically different, and, in fact, may be - negatively affected by the initial configuration. This point argues - against premature optimization by the TCP implementation. - -2.7 Bandwidth Oscillation - - Given the limited RF spectrum, satisfying the high data rate needs of - 2.5G/3G wireless systems requires dynamic resource sharing among - concurrent data users. Various scheduling mechanisms can be deployed - in order to maximize resource utilization. If multiple users wish to - transfer large amounts of data at the same time, the scheduler may - have to repeatedly allocate and de-allocate resources for each user. - We refer to periodic allocation and release of high-speed channels as - Bandwidth Oscillation. Bandwidth Oscillation effects such as - spurious retransmissions were identified elsewhere (e.g., [30]) as - factors that degrade throughput. There are research studies [52], - [54], which show that in some cases Bandwidth Oscillation can be the - single most important factor in reducing throughput. For fixed TCP - parameters the achievable throughput depends on the pattern of - - - -Inamura, et al. Best Current Practice [Page 7] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - resource allocation. When the frequency of resource allocation and - de-allocation is sufficiently high, there is no throughput - degradation. However, increasing the frequency of resource - allocation/de-allocation may come at the expense of increased - signaling, and, therefore, may not be desirable. Standards for 3G - wireless technologies provide mechanisms that can be used to combat - the adverse effects of Bandwidth Oscillation. It is the consensus of - the PILC Working Group that the best approach for avoiding adverse - effects of Bandwidth Oscillation is proper wireless sub-network - design [23]. - -3. Example 2.5G and 3G Deployments - - This section provides further details on a few example 2.5G/3G - technologies. The objective is not completeness, but merely to - discuss some representative technologies and the issues that may - arise with TCP performance. Other documents discuss the underlying - technologies in more detail. For example, ARQ and FEC are discussed - in [23], while further justification for link layer ARQ is discussed - in [22], [44]. - -3.1 2.5G Technologies: GPRS, HSCSD and CDMA2000 1XRTT - - High Speed Circuit-Switched Data (HSCSD) and General Packet Radio - Service (GPRS) are extensions of GSM providing high data rates for a - user. Both extensions were developed first by ETSI and later by - 3GPP. In GSM, a user is assigned one timeslot downlink and one - uplink. HSCSD allocates multiple timeslots to a user creating a fast - circuit-switched link. GPRS is based on packet-switched technology - that allows efficient sharing of radio resources among users and - always-on capability. Several terminals can share timeslots. A GPRS - network uses an updated base station subsystem of GSM as the access - network; the GPRS core network includes Serving GPRS Support Nodes - (SGSN) and Gateway GPRS Support Nodes (GGSN). The RLC protocol - operating between a base station controller and a terminal provides - ARQ capability over the radio link. The Logical Link Control (LLC) - protocol between the SGSN and the terminal also has an ARQ capability - utilized during handovers. - -3.2 A 3G Technology: W-CDMA - - The International Telecommunication Union (ITU) has selected Wideband - Code Division Multiple Access (W-CDMA) as one of the global telecom - systems for the IMT-2000 3G mobile communications standard. W-CDMA - specifications are created in the 3rd Generation Partnership Project - (3GPP). - - - - - -Inamura, et al. Best Current Practice [Page 8] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - The link layer characteristics of the 3G network which have the - largest effect on TCP performance over the link are error controlling - schemes such as layer two ARQ (L2 ARQ) and FEC (forward error - correction). - - W-CDMA uses RLC (Radio Link Control) [20], a Selective Repeat and - sliding window ARQ. RLC uses protocol data units (PDUs) with a 16 - bit RLC header. The size of the PDUs may vary. Typically, 336 bit - PDUs are implemented [34]. This is the unit for link layer - retransmission. The IP packet is fragmented into PDUs for - transmission by RLC. (For more fragmentation discussion, see Section - 4.4.) - - In W-CDMA, one to twelve PDUs (RLC frames) constitute one FEC frame, - the actual size of which depends on link conditions and bandwidth - allocation. The FEC frame is the unit of interleaving. This - accumulation of PDUs for FEC adds part of the latency mentioned in - Section 2.1. - - For reliable transfer, RLC has an acknowledged mode for PDU - retransmission. RLC uses checkpoint ARQ [20] with "status report" - type acknowledgments; the poll bit in the header explicitly solicits - the peer for a status report containing the sequence number that the - peer acknowledges. The use of the poll bit is controlled by timers - and by the size of available buffer space in RLC. Also, when the - peer detects a gap between sequence numbers in received frames, it - can issue a status report to invoke retransmission. RLC preserves - the order of packet delivery. - - The maximum number of retransmissions is a configurable RLC parameter - that is specified by RRC [39] (Radio Resource Controller) through RLC - connection initialization. The RRC can set the maximum number of - retransmissions (up to a maximum of 40). Therefore, RLC can be - described as an ARQ that can be configured for either HIGH- - PERSISTENCE or LOW-PERSISTENCE, not PERFECT-PERSISTENCE, according to - the terminology in [22]. - - Since the RRC manages RLC connection state, Bandwidth Oscillation - (Section 2.7) can be eliminated by the RRC's keeping RF resource on - an RLC connection with data in its queue. This avoids resource de- - allocation in the middle of transferring data. - - In summary, the link layer ARQ and FEC can provide a packet service - with a negligibly small probability of undetected error (failure of - the link CRC), and a low level of loss (non-delivery) for the upper - layer traffic, i.e., IP. Retransmission of PDUs by ARQ introduces - latency and delay jitter to the IP flow. This is why the transport - layer sees the underlying W-CDMA network as a network with a - - - -Inamura, et al. Best Current Practice [Page 9] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - relatively large BDP (Bandwidth-Delay Product) of up to 50 KB for the - 384 kbps radio bearer. - -3.3 A 3G Technology: CDMA2000 1X-EV - - One of the Terrestrial Radio Interface standards for 3G wireless - systems, proposed under the International Mobile Telecommunications- - 2000 umbrella, is cdma2000 [55]. It employs Multi-Carrier Code - Division Multiple Access (CDMA) technology with a single-carrier RF - bandwidth of 1.25 MHz. cdma2000 evolved from IS-95 [56], a 2G - standard based on CDMA technology. The first phase of cdma2000 - utilizes a single carrier and is designed to double the voice - capacity of existing CDMA (IS-95) networks and to support always-on - data transmission speeds of up to 316.8 kbps. As mentioned above, - these enhanced capabilities are delivered by cdma2000 1XRTT. 3G - speeds of 2 Mbps are offered by cdma2000 1X-EV. At the physical - layer, the standard allows transmission in 5,10,20,40 or 80 ms time - frames. Various orthogonal (Walsh) codes are used for channel - identification and to achieve higher data rates. - - Radio Link Protocol Type 3 (RLP) [57] is used with a cdma2000 Traffic - Channel to support CDMA data services. RLP provides an octet stream - transport service and is unaware of higher layer framing. There are - several RLP frame formats. RLP frame formats with higher payload - were designed for higher data rates. Depending on the channel speed, - one or more RLP frames can be transmitted in a single physical layer - frame. - - RLP can substantially decrease the error rate exhibited by CDMA - traffic channels [53]. When transferring data, RLP is a pure NAK- - based finite selective repeat protocol. The receiver does not - acknowledge successfully received data frames. If one or more RLP - data frames are missing, the receiving RLP makes several attempts - (called NAK rounds) to recover them by sending one or more NAK - control frames to the transmitter. Each NAK frame must be sent in a - separate physical layer frame. When RLP supplies the last NAK - control frame of a particular NAK round, a retransmission timer is - set. If the missing frame is not received when the timer expires, - RLP may try another NAK round. RLP may not recover all missing - frames. If after all RLP rounds, a frame is still missing, RLP - supplies data with a missing frame to the higher layer protocols. - -4. TCP over 2.5G and 3G - - What follows is a set of recommendations for configuration parameters - for protocol stacks which will be used to support TCP connections - over 2.5G and 3G wireless networks. Some of these recommendations - imply special configuration: - - - -Inamura, et al. Best Current Practice [Page 10] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - o at the data receiver (frequently a stack at or near the wireless - device), - - o at the data sender (frequently a host in the Internet or possibly - a gateway or proxy at the edge of a wireless network), or - - o at both. - - These configuration options are commonly available IETF standards- - track mechanisms considered safe on the general Internet. System - administrators are cautioned, however, that increasing the MTU size - (Section 4.4) and disabling RFC 1144 header compression (Section 4.9) - could affect host efficiency, and that changing such parameters - should be done with care. - -4.1 Appropriate Window Size (Sender & Receiver) - - TCP over 2.5G/3G should support appropriate window sizes based on the - Bandwidth Delay Product (BDP) of the end-to-end path (see Section - 2.2). The TCP specification [14] limits the receiver window size to - 64 KB. If the end-to-end BDP is expected to be larger than 64 KB, - the window scale option [2] can be used to overcome that limitation. - Many operating systems by default use small TCP receive and send - buffers around 16KB. Therefore, even for a BDP below 64 KB, the - default buffer size setting should be increased at the sender and at - the receiver to allow a large enough window. - -4.2 Increased Initial Window (Sender) - - TCP controls its transmit rate using the congestion window mechanism. - The traditional initial window value of one segment, coupled with the - delayed ACK mechanism [17] implies unnecessary idle times in the - initial phase of the connection, including the delayed ACK timeout - (typically 200 ms, but potentially as much as 500 ms) [4]. Senders - can avoid this by using a larger initial window of up to four - segments (not to exceed roughly 4 KB) [4]. Experiments with - increased initial windows and related measurements have shown (1) - that it is safe to deploy this mechanism (i.e., it does not lead to - congestion collapse), and (2) that it is especially effective for the - transmission of a few TCP segments' worth of data (which is the - behavior commonly seen in such applications as Internet-enabled - mobile wireless devices). For large data transfers, on the other - hand, the effect of this mechanism is negligible. - - TCP over 2.5G/3G SHOULD set the initial CWND (congestion window) - according to Equation 1 in [4]: - - min (4*MSS, max (2*MSS, 4380 bytes)) - - - -Inamura, et al. Best Current Practice [Page 11] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - This increases the permitted initial window from one to between two - and four segments (not to exceed approximately 4 KB). - -4.3 Limited Transmit (Sender) - - RFC 3042 [10], Limited Transmit, extends Fast Retransmit/Fast - Recovery for TCP connections with small congestion windows that are - not likely to generate the three duplicate acknowledgements required - to trigger Fast Retransmit [1]. If a sender has previously unsent - data queued for transmission, the limited transmit mechanism calls - for sending a new data segment in response to each of the first two - duplicate acknowledgments that arrive at the sender. This mechanism - is effective when the congestion window size is small or if a large - number of segments in a window are lost. This may avoid some - retransmissions due to TCP timeouts. In particular, some studies - [10] have shown that over half of a busy server's retransmissions - were due to RTO expiration (as opposed to Fast Retransmit), and that - roughly 25% of those could have been avoided using Limited Transmit. - Similar to the discussion in Section 4.2, this mechanism is useful - for small amounts of data to be transmitted. TCP over 2.5G/3G - implementations SHOULD implement Limited Transmit. - -4.4 IP MTU Larger than Default - - The maximum size of an IP datagram supported by a link layer is the - MTU (Maximum Transfer Unit). The link layer may, in turn, fragment - IP datagrams into PDUs. For example, on links with high error rates, - a smaller link PDU size increases the chance of successful - transmission. With layer two ARQ and transparent link layer - fragmentation, the network layer can enjoy a larger MTU even in a - relatively high BER (Bit Error Rate) condition. Without these - features in the link, a smaller MTU is suggested. - - TCP over 2.5G/3G should allow freedom for designers to choose MTU - values ranging from small values (such as 576 bytes) to a large value - that is supported by the type of link in use (such as 1500 bytes for - IP packets on Ethernet). Given that the window is counted in units - of segments, a larger MTU allows TCP to increase the congestion - window faster [5]. Hence, designers are generally encouraged to - choose larger values. These may exceed the default IP MTU values of - 576 bytes for IPv4 RFC 1191 [6] and 1280 bytes for IPv6 [18]. While - this recommendation is applicable to 3G networks, operation over 2.5G - networks should exercise caution as per the recommendations in RFC - 3150 [5]. - - - - - - - -Inamura, et al. Best Current Practice [Page 12] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -4.5 Path MTU Discovery (Sender & Intermediate Routers) - - Path MTU discovery allows a sender to determine the maximum end-to- - end transmission unit (without IP fragmentation) for a given routing - path. RFC 1191 [6] and RFC 1981 [8] describe the MTU discovery - procedure for IPv4 and IPv6, respectively. This allows TCP senders - to employ larger segment sizes (without causing IP layer - fragmentation) instead of assuming the small default MTU. TCP over - 2.5G/3G implementations should implement Path MTU Discovery. Path - MTU Discovery requires intermediate routers to support the generation - of the necessary ICMP messages. RFC 1435 [7] provides - recommendations that may be relevant for some router implementations. - -4.6 Selective Acknowledgments (Sender & Receiver) - - The selective acknowledgment option (SACK), RFC 2018 [3], is - effective when multiple TCP segments are lost in a single TCP window - [24]. In particular, if the end-to-end path has a large BDP and a - high packet loss rate, the probability of multiple segment losses in - a single window of data increases. In such cases, SACK provides - robustness beyond TCP-Tahoe and TCP-Reno [21]. TCP over 2.5G/3G - SHOULD support SACK. - - In the absence of SACK feature, the TCP should use NewReno RFC 2582 - [15]. - -4.7 Explicit Congestion Notification (Sender, Receiver & Intermediate - Routers) - - Explicit Congestion Notification, RFC 3168 [9], allows a TCP receiver - to inform the sender of congestion in the network by setting the - ECN-Echo flag upon receiving an IP packet marked with the CE bit(s). - The TCP sender will then reduce its congestion window. Thus, the use - of ECN is believed to provide performance benefits [32], [43]. RFC - 3168 [9] also places requirements on intermediate routers (e.g., - active queue management and setting of the CE bit(s) in the IP header - to indicate congestion). Therefore, the potential improvement in - performance can only be achieved when ECN capable routers are - deployed along the path. TCP over 2.5G/3G SHOULD support ECN. - -4.8 TCP Timestamps Option (Sender & Receiver) - - Traditionally, TCPs collect one RTT sample per window of data [14], - [17]. This can lead to an underestimation of the RTT, and spurious - timeouts on paths in which the packet transmission delay dominates - the RTT. This holds despite a conservative retransmit timer such as - the one specified in RFC 2988 [11]. TCP connections with large - windows may benefit from more frequent RTT samples provided with - - - -Inamura, et al. Best Current Practice [Page 13] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - timestamps by adapting quicker to changing network conditions [2]. - However, there is some empirical evidence that for TCPs with an RFC - 2988 timer [11], timestamps provide little or no benefits on backbone - Internet paths [59]. Using the TCP Timestamps option has the - advantage that retransmitted segments can be used for RTT - measurement, which is otherwise forbidden by Karn's algorithm [17], - [11]. Furthermore, the TCP Timestamps option is the basis for - detecting spurious retransmits using the Eifel algorithm [30]. - - A 2.5/3G link (layer) is dedicated to a single host. It therefore - only experiences a low degree of statistical multiplexing between - different flows. Also, the packet transmission and queuing delays of - a 2.5/3G link often dominate the path's RTT. This already results in - large RTT variations as packets fill the queue while a TCP sender - probes for more bandwidth, or as packets drain from the queue while a - TCP sender reduces its load in response to a packet loss. In - addition, the delay spikes across a 2.5/3G link (see Section 2.4) may - often exceed the end-to-end RTT. The thus resulting large variations - in the path's RTT may often cause spurious timeouts. - - When running TCP in such an environment, it is therefore advantageous - to sample the path's RTT more often than only once per RTT. This - allows the TCP sender to track changes in the RTT more closely. In - particular, a TCP sender can react more quickly to sudden increases - of the RTT by sooner updating the RTO to a more conservative value. - The TCP Timestamps option [2] provides this capability, allowing the - TCP sender to sample the RTT from every segment that is acknowledged. - Using timestamps in the mentioned scenario leads to a more - conservative TCP retransmission timer and reduces the risk of - triggering spurious timeouts [45], [52], [54], [60]. - - There are two problematic issues with using timestamps: - - o 12 bytes of overhead are introduced by carrying the TCP Timestamps - option and padding in the TCP header. For a small MTU size, it - can present a considerable overhead. For example, for an MTU of - 296 bytes the added overhead is 4%. For an MTU of 1500 bytes, the - added overhead is only 0.8%. - - o Current TCP header compression schemes are limited in their - handling of the TCP options field. For RFC 2507 [13], any change - in the options field (caused by timestamps or SACK, for example) - renders the entire field uncompressible (leaving the TCP/IP header - itself compressible, however). Even worse, for RFC 1144 [40] such - a change in the options field effectively disables TCP/IP header - compression altogether. This is the case when a connection uses - the TCP Timestamps option. That option field is used both in the - data and the ACK path, and its value typically changes from one - - - -Inamura, et al. Best Current Practice [Page 14] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - packet to the next. The IETF is currently specifying a robust - TCP/IP header compression scheme with better support for TCP - options [29]. - - The original definition of the timestamps option [2] specifies that - duplicate segments below cumulative ACK do not update the cached - timestamp value at the receiver. This may lead to overestimating of - RTT for retransmitted segments. A possible solution [47] allows the - receiver to use a more recent timestamp from a duplicate segment. - However, this suggestion allows for spoofing attacks against the TCP - receiver. Therefore, careful consideration is needed in - implementing this solution. - - Recommendation: TCP SHOULD use the TCP Timestamps option. It allows - for better RTT estimation and reduces the risk of spurious timeouts. - -4.9 Disabling RFC 1144 TCP/IP Header Compression (Wireless Host) - - It is well known (and has been shown with experimental data) that RFC - 1144 [40] TCP header compression does not perform well in the - presence of packet losses [43], [52]. If a wireless link error is - not recovered, it will cause TCP segment loss between the compressor - and decompressor, and then RFC 1144 header compression does not allow - TCP to take advantage of Fast Retransmit Fast Recovery mechanism. - The RFC 1144 header compression algorithm does not transmit the - entire TCP/IP headers, but only the changes in the headers of - consecutive segments. Therefore, loss of a single TCP segment on the - link causes the transmitting and receiving TCP sequence numbers to - fall out of synchronization. Hence, when a TCP segment is lost - after the compressor, the decompressor will generate false TCP - headers. Consequently, the TCP receiver will discard all remaining - packets in the current window because of a checksum error. This - continues until the compressor receives the first retransmission - which is forwarded uncompressed to synchronize the decompressor [40]. - - As previously recommended in RFC 3150 [5], RFC 1144 header - compression SHOULD NOT be enabled unless the packet loss probability - between the compressor and decompressor is very low. Actually, - enabling the Timestamps Option effectively accomplishes the same - thing (see Section 4.8). Other header compression schemes like RFC - 2507 [13] and Robust Header Compression [12] are meant to address - deficiencies in RFC 1144 header compression. At the time of this - writing, the IETF was working on multiple extensions to Robust Header - Compression (negotiating Robust Header Compression over PPP, - compressing TCP options, etc) [16]. - - - - - - -Inamura, et al. Best Current Practice [Page 15] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -4.10 Summary - - Items Comments - ---------------------------------------------------------------- - Appropriate Window Size (sender & receiver) - based on end-to-end BDP - - Window Scale Option (sender & receiver) - [RFC1323] Window size > 64KB - - Increased Initial Window (sender) - [RFC3390] CWND = min (4*MSS, - max (2*MSS, 4380 bytes)) - - Limited Transmit (sender) - [RFC3042] - - IP MTU larger than more applicable to 3G - Default - - Path MTU Discovery (sender & intermediate routers) - [RFC1191,RFC1981] - - Selective Acknowledgment - option (SACK) - [RFC2018] (sender & receiver) - - Explicit Congestion - Notification(ECN) - [RFC3168] (sender, receiver & - intermediate routers) - - Timestamps Option (sender & receiver) - [RFC1323, R.T.Braden's ID] - - Disabling RFC1144 - TCP/IP Header Compression - [RFC1144] (wireless host) - -5. Open Issues - - This section outlines additional mechanisms and parameter settings - that may increase end-to-end performance when running TCP across - 2.5G/3G networks. Note, that apart from the discussion of the RTO's - initial value, those mechanisms and parameter settings are not part - of any standards track RFC at the time of this writing. Therefore, - they cannot be recommended for the Internet in general. - - - - -Inamura, et al. Best Current Practice [Page 16] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - Other mechanisms for increasing TCP performance include enhanced TCP/ - IP header compression schemes [29], active queue management RFC 2309 - [28], link layer retransmission schemes [23], and caching packets - during transient link outages to retransmit them locally when the - link is restored to operation [23]. - - Shortcomings of existing TCP/IP header compression schemes (RFC 1144 - [40], RFC 2507 [13]) are that they do not compress headers of - handshaking packets (SYNs and FINs), and that they lack proper - handling of TCP option fields (e.g., SACK or timestamps) (see Section - 4.8). Although RFC 3095 [12] does not yet address this issue, the - IETF is developing improved TCP/IP header compression schemes, - including better handling of TCP options such as timestamps and - selective acknowledgements. Especially, if many short-lived TCP - connections run across the link, the compression of the handshaking - packets may greatly improve the overall header compression ratio. - - Implementing active queue management is attractive for a number of - reasons as outlined in RFC 2309 [28]. One important benefit for - 2.5G/ 3G networks, is that it minimizes the amount of potentially - stale data that may be queued in the network ("clicking from page to - page" before the download of the previous page is complete). - Avoiding the transmission of stale data across the 2.5G/3G radio link - saves transmission (battery) power, and increases the ratio of useful - data over total data transmitted. Another important benefit of - active queue management for 2.5G/3G networks, is that it reduces the - risk of a spurious timeout for the first data segment as outlined - below. - - Since 2.5G/3G networks are commonly characterized by high delays, - avoiding unecessary round-trip times is particularly attractive. - This is specially beneficial for short-lived, transactional (request/ - response-style) TCP sessions that typically result from browsing the - Web from a smart phone. However, existing solutions such as T/TCP - RFC 1644 [27], have not been adopted due to known security concerns - [38]. - - Spurious timeouts, packet re-ordering, and packet duplication may - reduce TCP's performance. Thus, making TCP more robust against those - events is desirable. Solutions to this problem have been proposed - [30], [35], [41], and standardization work within the IETF is ongoing - at the time of writing. Those solutions include reverting congestion - control state after such an event has been detected, and adapting the - retransmission timer and duplicate acknowledgement threshold. The - deployment of such solutions may be particularly beneficial when - running TCP across wireless networks because wireless access links - may often be subject to handovers and resource preemption, or the - mobile transmitter may traverse through a radio coverage hole. Such - - - -Inamura, et al. Best Current Practice [Page 17] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - disrupting events may easily trigger a spurious timeout despite a - conservative retransmission timer. Also, the mobility mechanisms of - some wireless networks may cause packet duplication. - - The algorithm for computing TCP's retransmission timer is specified - in RFC 2988 [11]. The standard specifies that the initial setting of - the retransmission timeout value (RTO) should not be less than 3 - seconds. This value might be too low when running TCP across 2.5G/3G - networks. In addition to its high latencies, those networks may be - run at bit rates of as low as about 10 kb/s which results in large - packet transmission delays. In this case, the RTT for the first data - segment may easily exceed the initial TCP retransmission timer - setting of 3 seconds. This would then cause a spurious timeout for - that segment. Hence, in such situations it may be advisable to set - TCP's initial RTO to a value larger than 3 seconds. Furthermore, due - to the potentially large packet transmission delays, a TCP sender - might choose to refrain from initializing its RTO from the RTT - measured for the SYN, but instead take the RTT measured for the first - data segment. - - Some of the recommendations in RFC 2988 [11] are optional, and are - not followed by all TCP implementations. Specifically, some TCP - stacks allow a minimum RTO less than the recommended value of 1 - second (section 2.4 of [11]), and some implementations do not - implement the recommended restart of the RTO timer when an ACK is - received (section 5.3 of [11]). Some experiments [52], [54], have - shown that in the face of bandwidth oscillation, using the - recommended minimum RTO value of 1 sec (along with the also - recommended initial RTO of 3 sec) reduces the number of spurious - retransmissions as compared to using small minimum RTO values of 200 - or 400 ms. Furthermore, TCP stacks that restart the retransmission - timer when an ACK is received experience far less spurious - retransmissions than implementations that do not restart the RTO - timer when an ACK is received. Therefore, at the time of this - writing, it seems preferable for TCP implementations used in 3G - wireless data transmission to comply with all recommendations of RFC - 2988. - -6. Security Considerations - - In 2.5G/3G wireless networks, data is transmitted as ciphertext over - the air and as cleartext between the Radio Access Network (RAN) and - the core network. IP security RFC 2401 [37] or TLS RFC 2246 [36] can - be deployed by user devices for end-to-end security. - -7. IANA Considerations - - This specification requires no IANA actions. - - - -Inamura, et al. Best Current Practice [Page 18] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -8. Acknowledgements - - The authors would like to acknowledge contributions to the text from - the following individuals: - - Max Hata, NTT DoCoMo, Inc. (hata@mml.yrp.nttdocomo.co.jp) - - Masahiro Hara, Fujitsu, Inc. (mhara@FLAB.FUJITSU.CO.JP) - - Joby James, Motorola, Inc. (joby@MIEL.MOT.COM) - - William Gilliam, Hewlett-Packard Company (wag@cup.hp.com) - - Alan Hameed, Fujitsu FNC, Inc. (Alan.Hameed@fnc.fujitsu.com) - - Rodrigo Garces, Mobility Network Systems - (rodrigo.garces@mobilitynetworks.com) - - Peter Ford, Microsoft (peterf@Exchange.Microsoft.com) - - Fergus Wills, Openwave (fergus.wills@openwave.com) - - Michael Meyer (Michael.Meyer@eed.ericsson.se) - - The authors gratefully acknowledge the valuable advice from the - following individuals: - - Gorry Fairhurst (gorry@erg.abdn.ac.uk) - - Mark Allman (mallman@grc.nasa.gov) - - Aaron Falk (falk@ISI.EDU) - -9. Normative References - - [1] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion Control", - RFC 2581, April 1999. - - [2] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions for High - Performance", RFC 1323, May 1992. - - [3] Mathis, M., Mahdavi, J., Floyd, S. and R. Romanow, "TCP - Selective Acknowledgment Options", RFC 2018, October 1996. - - [4] Allman, M., Floyd, S. and C. Partridge, "Increasing TCP's - Initial Window", RFC 3390, October 2002. - - - - - -Inamura, et al. Best Current Practice [Page 19] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - [5] Dawkins, S., Montenegro, G., Kojo, M. and V. Magret, "End-to-end - Performance Implications of Slow Links", BCP 48, RFC 3150, July - 2001. - - [6] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191, - November 1990. - - [7] Knowles, S., "IESG Advice from Experience with Path MTU - Discovery", RFC 1435, March 1993. - - [8] McCann, J., Deering, S. and J. Mogul, "Path MTU Discovery for IP - version 6", RFC 1981, August 1996. - - [9] Ramakrishnan, K., Floyd, S. and D. Black, "The Addition of - Explicit Congestion Notification (ECN) to IP", RFC 3168, - September 2001. - - [10] Allman, M., Balakrishnan, H. and S. Floyd, "Enhancing TCP's Loss - Recovery Using Limited Transmit", RFC 3042, January 2001. - - [11] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [12] Bormann, C., Burmeister, C., Degermark, M., Fukushima, H., - Hannu, H., Jonsson, L-E., Hakenberg, R., Koren, T., Le, K., Liu, - Z., Martensson, A., Miyazaki, A., Svanbro, K., Wiebke, T., - Yoshimura, T. and H. Zheng, "RObust Header Compression (ROHC): - Framework and four profiles: RTP, UDP, ESP, and uncompressed", - RFC 3095, July 2001. - - [13] Degermark, M., Nordgren, B. and S. Pink, "IP Header - Compression", RFC 2507, February 1999. - - [14] Postel, J., "Transmission Control Protocol - DARPA Internet - Program Protocol Specification", STD 7, RFC 793, September 1981. - - [15] Floyd, S. and T. Henderson, "The NewReno Modification to TCP's - Fast Recovery Algorithm", RFC 2582, April 1999. - - [16] Bormann, C., "Robust Header Compression (ROHC) over PPP", RFC - 3241, April 2002. - - [17] Braden, R., "Requirements for Internet Hosts - Communication - Layers", STD 3, RFC 1122, October 1989. - - [18] Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) - Specification", RFC 2460, December 1998. - - - - -Inamura, et al. Best Current Practice [Page 20] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -10. Informative References - - [19] Montenegro, G., Dawkins, S., Kojo, M., Magret, V. and N. - Vaidya, "Long Thin Networks", RFC 2757, January 2000. - - [20] Third Generation Partnership Project, "RLC Protocol - Specification (3G TS 25.322:)", 1999. - - [21] Fall, K. and S. Floyd, "Simulation-based Comparisons of Tahoe, - Reno, and SACK TCP", Computer Communication Review, 26(3) , July - 1996. - - [22] Fairhurst, G. and L. Wood, "Advice to link designers on link - Automatic Repeat reQuest (ARQ)", BCP 62, RFC 3366, August 2002. - - [23] Karn, P., "Advice for Internet Subnetwork Designers", Work in - Progress. - - [24] Dawkins, S., Montenegro, G., Magret, V., Vaidya, N. and M. - Kojo, "End-to-end Performance Implications of Links with - Errors", BCP 50, RFC 3135, August 2001. - - [25] Wireless Application Protocol, "WAP Specifications", 2002, - . - - [26] Open Mobile Alliance, "Open Mobile Alliance", 2002, - . - - [27] Braden, R., "T/TCP -- TCP Extensions for Transactions", RFC - 1644, July 1994. - - [28] Braden, R., Clark, D., Crowcroft, J., Davie, B., Deering, S., - Estrin, D., Floyd, S., Jacobson, V., Minshall, G., Partridge, - C., Peterson, L., Ramakrishnan, K., Shenker, S., Wroclawski, J. - and L. Zhang, "Recommendations on Queue Management and - Congestion Avoidance in the Internet", RFC 2309, April 1998. - - [29] IETF, "Robust Header Compression", 2001, - . - - [30] Ludwig, R. and R. H. Katz, "The Eifel Algorithm: Making TCP - Robust Against Spurious Retransmissions", ACM Computer - Communication Review 30(1), January 2000. - - [31] Wireless Application Protocol, "WAP Wireless Profiled TCP", - WAP-225-TCP-20010331-a, April 2001, - . - - - - -Inamura, et al. Best Current Practice [Page 21] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - [32] Hadi Salim, J. and U. Ahmed, "Performance Evaluation of Explicit - Congestion Notification (ECN) in IP Networks", RFC 2884, July - 2000. - - [33] NTT DoCoMo Technical Journal, "Special Issue on i-mode Service", - October 1999. - - [34] NTT DoCoMo Technical Journal, "Special Article on IMT-2000 - Services", September 2001. - - [35] Floyd, S., Mahdavi, J., Mathis, M. and M. Podolsky, "An - Extension to the Selective Acknowledgement (SACK) Option for - TCP", RFC 2883, July 2000. - - [36] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC - 2246, January 1999. - - [37] Kent, S. and R. Atkinson, "Security Architecture for the - Internet Protocol", RFC 2401, November 1998. - - [38] de Vivo, M., O. de Vivo, G., Koeneke, R. and G. Isern, "Internet - Vulnerabilities Related to TCP/IP and T/TCP", ACM Computer - Communication Review 29(1), January 1999. - - [39] Third Generation Partnership Project, "RRC Protocol - Specification (3GPP TS 25.331:)", September 2001. - - [40] Jacobson, V., "Compressing TCP/IP Headers for Low-Speed Serial - Links", RFC 1144, February 1990. - - [41] Blanton, E. and M. Allman, "On Making TCP More Robust to Packet - Reordering", ACM Computer Communication Review 32(1), January - 2002, . - - [42] Karn, P. and C. Partridge, "Improving Round-Trip Time Estimates - in Reliable Transport Protocols", ACM SIGCOMM 87, 1987. - - [43] Ludwig, R., Rathonyi, B., Konrad, A. and A. Joseph, "Multi-layer - tracing of TCP over a reliable wireless link", ACM SIGMETRICS - 99, May 1999. - - [44] Ludwig, R., Konrad, A., Joseph, A. and R. Katz, "Optimizing the - End-to-End Performance of Reliable Flows over Wireless Links", - Kluwer/ACM Wireless Networks Journal Vol. 8, Nos. 2/3, pp. 289- - 299, March-May 2002. - - - - - -Inamura, et al. Best Current Practice [Page 22] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - [45] Gurtov, A., "Making TCP Robust Against Delay Spikes", University - of Helsinki, Department of Computer Science, Series of - Publications C, C-2001-53, Nov 2001, - . - - [46] Stevens, W., "TCP/IP Illustrated, Volume 1; The Protocols", - Addison Wesley, 1995. - - [47] Braden, R., "TCP Extensions for High Performance: An Update", - Work in Progress. - - [48] Allman, M., Dawkins, S., Glover, D., Griner, J., Tran, D., - Henderson, T., Heidemann, J., Touch, J., Kruse, H., Ostermann, - S., Scott, K. and J. Semke, "Ongoing TCP Research Related to - Satellites", RFC 2760, February 2000. - - [49] Allman, M., Glover, D. and L. Sanchez, "Enhancing TCP Over - Satellite Channels using Standard Mechanisms", BCP 28, RFC 2488, - January 1999. - - [50] Balakrishnan, H., Padmanabhan, V., Fairhurst, G. and M. - Sooriyabandara, "TCP Performance Implications of Network - Asymmetry", RFC 3449, December 2002. - - [51] Kempf, J., "Problem Description: Reasons For Performing Context - Transfers Between Nodes in an IP Access Network", RFC 3374, - September 2002. - - [52] Khafizov, F. and M. Yavuz, "Running TCP over IS-2000", Proc. of - IEEE ICC, 2002. - - [53] Khafizov, F. and M. Yavuz, "Analytical Model of RLP in IS-2000 - CDMA Networks", Proc. of IEEE Vehicular Technology Conference, - September 2002. - - [54] Yavuz, M. and F. Khafizov, "TCP over Wireless Links with - Variable Bandwidth", Proc. of IEEE Vehicular Technology - Conference, September 2002. - - [55] TIA/EIA/cdma2000, "Mobile Station - Base Station Compatibility - Standard for Dual-Mode Wideband Spread Spectrum Cellular - Systems", Washington: Telecommunication Industry Association, - 1999. - - [56] TIA/EIA/IS-95 Rev A, "Mobile Station - Base Station - Compatibility Standard for Dual-Mode Wideband Spread Spectrum - Cellular Systems", Washington: Telecommunication Industry - Association, 1995. - - - -Inamura, et al. Best Current Practice [Page 23] - -RFC 3481 TCP over 2.5G/3G February 2003 - - - [57] TIA/EIA/IS-707-A-2.10, "Data Service Options for Spread Spectrum - Systems: Radio Link Protocol Type 3", January 2000. - - [58] Dahlman, E., Beming, P., Knutsson, J., Ovesjo, F., Persson, M. - and C. Roobol, "WCDMA - The Radio Interface for Future Mobile - Multimedia Communications", IEEE Trans. on Vehicular Technology, - vol. 47, no. 4, pp. 1105-1118, November 1998. - - [59] Allman, M. and V. Paxson, "On Estimating End-to-End Network Path - Properties", ACM SIGCOMM 99, September 1999. - - [60] Gurtov, A. and R. Ludwig, "Responding to Spurious Timeouts in - TCP", IEEE INFOCOM'03, March 2003. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Inamura, et al. Best Current Practice [Page 24] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -11. Authors' Addresses - - Hiroshi Inamura - NTT DoCoMo, Inc. - 3-5 Hikarinooka - Yokosuka Shi, Kanagawa Ken 239-8536 - Japan - - EMail: inamura@mml.yrp.nttdocomo.co.jp - URI: http://www.nttdocomo.co.jp/ - - - Gabriel Montenegro - Sun Microsystems Laboratories, Europe - Avenue de l'Europe - ZIRST de Montbonnot - 38334 Saint Ismier CEDEX - France - - EMail: gab@sun.com - - - Reiner Ludwig - Ericsson Research - Ericsson Allee 1 - 52134 Herzogenrath - Germany - - EMail: Reiner.Ludwig@Ericsson.com - - - Andrei Gurtov - Sonera - P.O. Box 970, FIN-00051 - Helsinki, - Finland - - EMail: andrei.gurtov@sonera.com - URI: http://www.cs.helsinki.fi/u/gurtov/ - - - Farid Khafizov - Nortel Networks - 2201 Lakeside Blvd - Richardson, TX 75082, - USA - - EMail: faridk@nortelnetworks.com - - - -Inamura, et al. Best Current Practice [Page 25] - -RFC 3481 TCP over 2.5G/3G February 2003 - - -12. Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Inamura, et al. Best Current Practice [Page 26] - diff --git a/ext/picotcp/RFC/rfc3517.txt b/ext/picotcp/RFC/rfc3517.txt deleted file mode 100644 index f5eeb61..0000000 --- a/ext/picotcp/RFC/rfc3517.txt +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - -Network Working Group E. Blanton -Request for Comments: 3517 Purdue University -Category: Standards Track M. Allman - BBN/NASA GRC - K. Fall - Intel Research - L. Wang - University of Kentucky - April 2003 - - - A Conservative Selective Acknowledgment (SACK)-based - Loss Recovery Algorithm for TCP - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - This document presents a conservative loss recovery algorithm for TCP - that is based on the use of the selective acknowledgment (SACK) TCP - option. The algorithm presented in this document conforms to the - spirit of the current congestion control specification (RFC 2581), - but allows TCP senders to recover more effectively when multiple - segments are lost from a single flight of data. - -Terminology - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. - - - - - - - - - - -Blanton, et al. Standards Track [Page 1] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - -1 Introduction - - This document presents a conservative loss recovery algorithm for TCP - that is based on the use of the selective acknowledgment (SACK) TCP - option. While the TCP SACK [RFC2018] is being steadily deployed in - the Internet [All00], there is evidence that hosts are not using the - SACK information when making retransmission and congestion control - decisions [PF01]. The goal of this document is to outline one - straightforward method for TCP implementations to use SACK - information to increase performance. - - [RFC2581] allows advanced loss recovery algorithms to be used by TCP - [RFC793] provided that they follow the spirit of TCP's congestion - control algorithms [RFC2581, RFC2914]. [RFC2582] outlines one such - advanced recovery algorithm called NewReno. This document outlines a - loss recovery algorithm that uses the SACK [RFC2018] TCP option to - enhance TCP's loss recovery. The algorithm outlined in this - document, heavily based on the algorithm detailed in [FF96], is a - conservative replacement of the fast recovery algorithm [Jac90, - RFC2581]. The algorithm specified in this document is a - straightforward SACK-based loss recovery strategy that follows the - guidelines set in [RFC2581] and can safely be used in TCP - implementations. Alternate SACK-based loss recovery methods can be - used in TCP as implementers see fit (as long as the alternate - algorithms follow the guidelines provided in [RFC2581]). Please - note, however, that the SACK-based decisions in this document (such - as what segments are to be sent at what time) are largely decoupled - from the congestion control algorithms, and as such can be treated as - separate issues if so desired. - -2 Definitions - - The reader is expected to be familiar with the definitions given in - [RFC2581]. - - The reader is assumed to be familiar with selective acknowledgments - as specified in [RFC2018]. - - For the purposes of explaining the SACK-based loss recovery algorithm - we define four variables that a TCP sender stores: - - "HighACK" is the sequence number of the highest byte of data that - has been cumulatively ACKed at a given point. - - "HighData" is the highest sequence number transmitted at a given - point. - - - - - -Blanton, et al. Standards Track [Page 2] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - "HighRxt" is the highest sequence number which has been - retransmitted during the current loss recovery phase. - - "Pipe" is a sender's estimate of the number of bytes outstanding - in the network. This is used during recovery for limiting the - sender's sending rate. The pipe variable allows TCP to use a - fundamentally different congestion control than specified in - [RFC2581]. The algorithm is often referred to as the "pipe - algorithm". - - For the purposes of this specification we define a "duplicate - acknowledgment" as a segment that arrives with no data and an - acknowledgment (ACK) number that is equal to the current value of - HighACK, as described in [RFC2581]. - - We define a variable "DupThresh" that holds the number of duplicate - acknowledgments required to trigger a retransmission. Per [RFC2581] - this threshold is defined to be 3 duplicate acknowledgments. - However, implementers should consult any updates to [RFC2581] to - determine the current value for DupThresh (or method for determining - its value). - - Finally, a range of sequence numbers [A,B] is said to "cover" - sequence number S if A <= S <= B. - -3 Keeping Track of SACK Information - - For a TCP sender to implement the algorithm defined in the next - section it must keep a data structure to store incoming selective - acknowledgment information on a per connection basis. Such a data - structure is commonly called the "scoreboard". The specifics of the - scoreboard data structure are out of scope for this document (as long - as the implementation can perform all functions required by this - specification). - - Note that this document refers to keeping account of (marking) - individual octets of data transferred across a TCP connection. A - real-world implementation of the scoreboard would likely prefer to - manage this data as sequence number ranges. The algorithms presented - here allow this, but require arbitrary sequence number ranges to be - marked as having been selectively acknowledged. - - - - - - - - - - -Blanton, et al. Standards Track [Page 3] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - -4 Processing and Acting Upon SACK Information - - For the purposes of the algorithm defined in this document the - scoreboard SHOULD implement the following functions: - - Update (): - - Given the information provided in an ACK, each octet that is - cumulatively ACKed or SACKed should be marked accordingly in the - scoreboard data structure, and the total number of octets SACKed - should be recorded. - - Note: SACK information is advisory and therefore SACKed data MUST - NOT be removed from TCP's retransmission buffer until the data is - cumulatively acknowledged [RFC2018]. - - IsLost (SeqNum): - - This routine returns whether the given sequence number is - considered to be lost. The routine returns true when either - DupThresh discontiguous SACKed sequences have arrived above - 'SeqNum' or (DupThresh * SMSS) bytes with sequence numbers greater - than 'SeqNum' have been SACKed. Otherwise, the routine returns - false. - - SetPipe (): - - This routine traverses the sequence space from HighACK to HighData - and MUST set the "pipe" variable to an estimate of the number of - octets that are currently in transit between the TCP sender and - the TCP receiver. After initializing pipe to zero the following - steps are taken for each octet 'S1' in the sequence space between - HighACK and HighData that has not been SACKed: - - (a) If IsLost (S1) returns false: - - Pipe is incremented by 1 octet. - - The effect of this condition is that pipe is incremented for - packets that have not been SACKed and have not been determined - to have been lost (i.e., those segments that are still assumed - to be in the network). - - (b) If S1 <= HighRxt: - - Pipe is incremented by 1 octet. - - - - - -Blanton, et al. Standards Track [Page 4] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - The effect of this condition is that pipe is incremented for - the retransmission of the octet. - - Note that octets retransmitted without being considered lost are - counted twice by the above mechanism. - - NextSeg (): - - This routine uses the scoreboard data structure maintained by the - Update() function to determine what to transmit based on the SACK - information that has arrived from the data receiver (and hence - been marked in the scoreboard). NextSeg () MUST return the - sequence number range of the next segment that is to be - transmitted, per the following rules: - - (1) If there exists a smallest unSACKed sequence number 'S2' that - meets the following three criteria for determining loss, the - sequence range of one segment of up to SMSS octets starting - with S2 MUST be returned. - - (1.a) S2 is greater than HighRxt. - - (1.b) S2 is less than the highest octet covered by any - received SACK. - - (1.c) IsLost (S2) returns true. - - (2) If no sequence number 'S2' per rule (1) exists but there - exists available unsent data and the receiver's advertised - window allows, the sequence range of one segment of up to SMSS - octets of previously unsent data starting with sequence number - HighData+1 MUST be returned. - - (3) If the conditions for rules (1) and (2) fail, but there exists - an unSACKed sequence number 'S3' that meets the criteria for - detecting loss given in steps (1.a) and (1.b) above - (specifically excluding step (1.c)) then one segment of up to - SMSS octets starting with S3 MAY be returned. - - Note that rule (3) is a sort of retransmission "last resort". - It allows for retransmission of sequence numbers even when the - sender has less certainty a segment has been lost than as with - rule (1). Retransmitting segments via rule (3) will help - sustain TCP's ACK clock and therefore can potentially help - avoid retransmission timeouts. However, in sending these - segments the sender has two copies of the same data considered - to be in the network (and also in the Pipe estimate). When an - ACK or SACK arrives covering this retransmitted segment, the - - - -Blanton, et al. Standards Track [Page 5] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - sender cannot be sure exactly how much data left the network - (one of the two transmissions of the packet or both - transmissions of the packet). Therefore the sender may - underestimate Pipe by considering both segments to have left - the network when it is possible that only one of the two has. - - We believe that the triggering of rule (3) will be rare and - that the implications are likely limited to corner cases - relative to the entire recovery algorithm. Therefore we leave - the decision of whether or not to use rule (3) to - implementors. - - (4) If the conditions for each of (1), (2), and (3) are not met, - then NextSeg () MUST indicate failure, and no segment is - returned. - - Note: The SACK-based loss recovery algorithm outlined in this - document requires more computational resources than previous TCP loss - recovery strategies. However, we believe the scoreboard data - structure can be implemented in a reasonably efficient manner (both - in terms of computation complexity and memory usage) in most TCP - implementations. - -5 Algorithm Details - - Upon the receipt of any ACK containing SACK information, the - scoreboard MUST be updated via the Update () routine. - - Upon the receipt of the first (DupThresh - 1) duplicate ACKs, the - scoreboard is to be updated as normal. Note: The first and second - duplicate ACKs can also be used to trigger the transmission of - previously unsent segments using the Limited Transmit algorithm - [RFC3042]. - - When a TCP sender receives the duplicate ACK corresponding to - DupThresh ACKs, the scoreboard MUST be updated with the new SACK - information (via Update ()). If no previous loss event has occurred - on the connection or the cumulative acknowledgment point is beyond - the last value of RecoveryPoint, a loss recovery phase SHOULD be - initiated, per the fast retransmit algorithm outlined in [RFC2581]. - The following steps MUST be taken: - - (1) RecoveryPoint = HighData - - When the TCP sender receives a cumulative ACK for this data octet - the loss recovery phase is terminated. - - - - - -Blanton, et al. Standards Track [Page 6] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - (2) ssthresh = cwnd = (FlightSize / 2) - - The congestion window (cwnd) and slow start threshold (ssthresh) - are reduced to half of FlightSize per [RFC2581]. - - (3) Retransmit the first data segment presumed dropped -- the segment - starting with sequence number HighACK + 1. To prevent repeated - retransmission of the same data, set HighRxt to the highest - sequence number in the retransmitted segment. - - (4) Run SetPipe () - - Set a "pipe" variable to the number of outstanding octets - currently "in the pipe"; this is the data which has been sent by - the TCP sender but for which no cumulative or selective - acknowledgment has been received and the data has not been - determined to have been dropped in the network. It is assumed - that the data is still traversing the network path. - - (5) In order to take advantage of potential additional available - cwnd, proceed to step (C) below. - - Once a TCP is in the loss recovery phase the following procedure MUST - be used for each arriving ACK: - - (A) An incoming cumulative ACK for a sequence number greater than - RecoveryPoint signals the end of loss recovery and the loss - recovery phase MUST be terminated. Any information contained in - the scoreboard for sequence numbers greater than the new value of - HighACK SHOULD NOT be cleared when leaving the loss recovery - phase. - - (B) Upon receipt of an ACK that does not cover RecoveryPoint the - following actions MUST be taken: - - (B.1) Use Update () to record the new SACK information conveyed - by the incoming ACK. - - (B.2) Use SetPipe () to re-calculate the number of octets still - in the network. - - (C) If cwnd - pipe >= 1 SMSS the sender SHOULD transmit one or more - segments as follows: - - (C.1) The scoreboard MUST be queried via NextSeg () for the - sequence number range of the next segment to transmit (if any), - - - - - -Blanton, et al. Standards Track [Page 7] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - and the given segment sent. If NextSeg () returns failure (no - data to send) return without sending anything (i.e., terminate - steps C.1 -- C.5). - - (C.2) If any of the data octets sent in (C.1) are below HighData, - HighRxt MUST be set to the highest sequence number of the - retransmitted segment. - - (C.3) If any of the data octets sent in (C.1) are above HighData, - HighData must be updated to reflect the transmission of - previously unsent data. - - (C.4) The estimate of the amount of data outstanding in the - network must be updated by incrementing pipe by the number of - octets transmitted in (C.1). - - (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1) - -5.1 Retransmission Timeouts - - In order to avoid memory deadlocks, the TCP receiver is allowed to - discard data that has already been selectively acknowledged. As a - result, [RFC2018] suggests that a TCP sender SHOULD expunge the SACK - information gathered from a receiver upon a retransmission timeout - "since the timeout might indicate that the data receiver has - reneged." Additionally, a TCP sender MUST "ignore prior SACK - information in determining which data to retransmit." However, a - SACK TCP sender SHOULD still use all SACK information made available - during the slow start phase of loss recovery following an RTO. - - If an RTO occurs during loss recovery as specified in this document, - RecoveryPoint MUST be set to HighData. Further, the new value of - RecoveryPoint MUST be preserved and the loss recovery algorithm - outlined in this document MUST be terminated. In addition, a new - recovery phase (as described in section 5) MUST NOT be initiated - until HighACK is greater than or equal to the new value of - RecoveryPoint. - - As described in Sections 4 and 5, Update () SHOULD continue to be - used appropriately upon receipt of ACKs. This will allow the slow - start recovery period to benefit from all available information - provided by the receiver, despite the fact that SACK information was - expunged due to the RTO. - - If there are segments missing from the receiver's buffer following - processing of the retransmitted segment, the corresponding ACK will - contain SACK information. In this case, a TCP sender SHOULD use this - SACK information when determining what data should be sent in each - - - -Blanton, et al. Standards Track [Page 8] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - segment of the slow start. The exact algorithm for this selection is - not specified in this document (specifically NextSeg () is - inappropriate during slow start after an RTO). A relatively - straightforward approach to "filling in" the sequence space reported - as missing should be a reasonable approach. - -6 Managing the RTO Timer - - The standard TCP RTO estimator is defined in [RFC2988]. Due to the - fact that the SACK algorithm in this document can have an impact on - the behavior of the estimator, implementers may wish to consider how - the timer is managed. [RFC2988] calls for the RTO timer to be - re-armed each time an ACK arrives that advances the cumulative ACK - point. Because the algorithm presented in this document can keep the - ACK clock going through a fairly significant loss event, - (comparatively longer than the algorithm described in [RFC2581]), on - some networks the loss event could last longer than the RTO. In this - case the RTO timer would expire prematurely and a segment that need - not be retransmitted would be resent. - - Therefore we give implementers the latitude to use the standard - [RFC2988] style RTO management or, optionally, a more careful variant - that re-arms the RTO timer on each retransmission that is sent during - recovery MAY be used. This provides a more conservative timer than - specified in [RFC2988], and so may not always be an attractive - alternative. However, in some cases it may prevent needless - retransmissions, go-back-N transmission and further reduction of the - congestion window. - -7 Research - - The algorithm specified in this document is analyzed in [FF96], which - shows that the above algorithm is effective in reducing transfer time - over standard TCP Reno [RFC2581] when multiple segments are dropped - from a window of data (especially as the number of drops increases). - [AHKO97] shows that the algorithm defined in this document can - greatly improve throughput in connections traversing satellite - channels. - -8 Security Considerations - - The algorithm presented in this paper shares security considerations - with [RFC2581]. A key difference is that an algorithm based on SACKs - is more robust against attackers forging duplicate ACKs to force the - TCP sender to reduce cwnd. With SACKs, TCP senders have an - additional check on whether or not a particular ACK is legitimate. - While not fool-proof, SACK does provide some amount of protection in - this area. - - - -Blanton, et al. Standards Track [Page 9] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - -Acknowledgments - - The authors wish to thank Sally Floyd for encouraging this document - and commenting on early drafts. The algorithm described in this - document is loosely based on an algorithm outlined by Kevin Fall and - Sally Floyd in [FF96], although the authors of this document assume - responsibility for any mistakes in the above text. Murali Bashyam, - Ken Calvert, Tom Henderson, Reiner Ludwig, Jamshid Mahdavi, Matt - Mathis, Shawn Ostermann, Vern Paxson and Venkat Venkatsubra provided - valuable feedback on earlier versions of this document. We thank - Matt Mathis and Jamshid Mahdavi for implementing the scoreboard in ns - and hence guiding our thinking in keeping track of SACK state. - - The first author would like to thank Ohio University and the Ohio - University Internetworking Research Group for supporting the bulk of - his work on this project. - -Normative References - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgment Options", RFC 2018, October 1996. - - [RFC2026] Bradner, S., "The Internet Standards Process -- Revision - 3", BCP 9, RFC 2026, October 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2581] Allman, M., Paxson, V. and R. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - -Informative References - - [AHKO97] Mark Allman, Chris Hayes, Hans Kruse, Shawn Ostermann. TCP - Performance Over Satellite Links. Proceedings of the Fifth - International Conference on Telecommunications Systems, - Nashville, TN, March, 1997. - - [All00] Mark Allman. A Web Server's View of the Transport Layer. - ACM Computer Communication Review, 30(5), October 2000. - - [FF96] Kevin Fall and Sally Floyd. Simulation-based Comparisons - of Tahoe, Reno and SACK TCP. Computer Communication - Review, July 1996. - - - - -Blanton, et al. Standards Track [Page 10] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - - [Jac90] Van Jacobson. Modified TCP Congestion Avoidance Algorithm. - Technical Report, LBL, April 1990. - - [PF01] Jitendra Padhye, Sally Floyd. Identifying the TCP Behavior - of Web Servers, ACM SIGCOMM, August 2001. - - [RFC2582] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [RFC2914] Floyd, S., "Congestion Control Principles", BCP 41, RFC - 2914, September 2000. - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [RFC3042] Allman, M., Balakrishnan, H, and S. Floyd, "Enhancing TCP's - Loss Recovery Using Limited Transmit", RFC 3042, January - 2001. - -Intellectual Property Rights Notice - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights which may cover technology that may be required to practice - this standard. Please address the information to the IETF Executive - Director. - - - - - - - - - - - -Blanton, et al. Standards Track [Page 11] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - -Authors' Addresses - - Ethan Blanton - Purdue University Computer Sciences - 1398 Computer Science Building - West Lafayette, IN 47907 - - EMail: eblanton@cs.purdue.edu - - - Mark Allman - BBN Technologies/NASA Glenn Research Center - Lewis Field - 21000 Brookpark Rd. MS 54-5 - Cleveland, OH 44135 - - Phone: 216-433-6586 - Fax: 216-433-8705 - EMail: mallman@bbn.com - http://roland.grc.nasa.gov/~mallman - - - Kevin Fall - Intel Research - 2150 Shattuck Ave., PH Suite - Berkeley, CA 94704 - - EMail: kfall@intel-research.net - - - Lili Wang - Laboratory for Advanced Networking - 210 Hardymon Building - University of Kentucky - Lexington, KY 40506-0495 - - EMail: lwang0@uky.edu - - - - - - - - - - - - - - -Blanton, et al. Standards Track [Page 12] - -RFC 3517 SACK-based Loss Recovery for TCP April 2003 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Blanton, et al. Standards Track [Page 13] - diff --git a/ext/picotcp/RFC/rfc3522.txt b/ext/picotcp/RFC/rfc3522.txt deleted file mode 100644 index 4f48546..0000000 --- a/ext/picotcp/RFC/rfc3522.txt +++ /dev/null @@ -1,787 +0,0 @@ - - - - - - -Network Working Group R. Ludwig -Request for Comments: 3522 M. Meyer -Category: Experimental Ericsson Research - April 2003 - - - The Eifel Detection Algorithm for TCP - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - The Eifel detection algorithm allows a TCP sender to detect a - posteriori whether it has entered loss recovery unnecessarily. It - requires that the TCP Timestamps option defined in RFC 1323 be - enabled for a connection. The Eifel detection algorithm makes use of - the fact that the TCP Timestamps option eliminates the retransmission - ambiguity in TCP. Based on the timestamp of the first acceptable ACK - that arrives during loss recovery, it decides whether loss recovery - was entered unnecessarily. The Eifel detection algorithm provides a - basis for future TCP enhancements. This includes response algorithms - to back out of loss recovery by restoring a TCP sender's congestion - control state. - -Terminology - - The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, - SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this - document, are to be interpreted as described in [RFC2119]. - - We refer to the first-time transmission of an octet as the 'original - transmit'. A subsequent transmission of the same octet is referred - to as a 'retransmit'. In most cases, this terminology can likewise - be applied to data segments as opposed to octets. However, with - repacketization, a segment can contain both first-time transmissions - and retransmissions of octets. In that case, this terminology is - only consistent when applied to octets. For the Eifel detection - algorithm, this makes no difference as it also operates correctly - when repacketization occurs. - - - -Ludwig & Meyer Experimental [Page 1] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - We use the term 'acceptable ACK' as defined in [RFC793]. That is an - ACK that acknowledges previously unacknowledged data. We use the - term 'duplicate ACK', and the variable 'dupacks' as defined in - [WS95]. The variable 'dupacks' is a counter of duplicate ACKs that - have already been received by a TCP sender before the fast retransmit - is sent. We use the variable 'DupThresh' to refer to the so-called - duplicate acknowledgement threshold, i.e., the number of duplicate - ACKs that need to arrive at a TCP sender to trigger a fast - retransmit. Currently, DupThresh is specified as a fixed value of - three [RFC2581]. Future TCPs might implement an adaptive DupThresh. - -1. Introduction - - The retransmission ambiguity problem [Zh86], [KP87] is a TCP sender's - inability to distinguish whether the first acceptable ACK that - arrives after a retransmit was sent in response to the original - transmit or the retransmit. This problem occurs after a timeout- - based retransmit and after a fast retransmit. The Eifel detection - algorithm uses the TCP Timestamps option defined in [RFC1323] to - eliminate the retransmission ambiguity. It thereby allows a TCP - sender to detect a posteriori whether it has entered loss recovery - unnecessarily. - - This added capability of a TCP sender is useful in environments where - TCP's loss recovery and congestion control algorithms may often get - falsely triggered. This can be caused by packet reordering, packet - duplication, or a sudden delay increase in the data or the ACK path - that results in a spurious timeout. For example, such sudden delay - increases can often occur in wide-area wireless access networks due - to handovers, resource preemption due to higher priority traffic - (e.g., voice), or because the mobile transmitter traverses through a - radio coverage hole (e.g., see [Gu01]). In such wireless networks, - the often unnecessary go-back-N retransmits that typically occur - after a spurious timeout create a serious problem. They decrease - end-to-end throughput, are useless load upon the network, and waste - transmission (battery) power. Note that across such networks the use - of timestamps is recommended anyway [RFC3481]. - - Based on the Eifel detection algorithm, a TCP sender may then choose - to implement dedicated response algorithms. One goal of such a - response algorithm would be to alleviate the consequences of a - falsely triggered loss recovery. This may include restoring the TCP - sender's congestion control state, and avoiding the mentioned - unnecessary go-back-N retransmits. Another goal would be to adapt - protocol parameters such as the duplicate acknowledgement threshold - [RFC2581], and the RTT estimators [RFC2988]. This is to reduce the - risk of falsely triggering TCP's loss recovery again as the - connection progresses. However, such response algorithms are outside - - - -Ludwig & Meyer Experimental [Page 2] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - the scope of this document. Note: The original proposal, the "Eifel - algorithm" [LK00], comprises both a detection and a response - algorithm. This document only defines the detection part. The - response part is defined in [LG03]. - - A key feature of the Eifel detection algorithm is that it already - detects, upon the first acceptable ACK that arrives during loss - recovery, whether a fast retransmit or a timeout was spurious. This - is crucial to be able to avoid the mentioned go-back-N retransmits. - Another feature is that the Eifel detection algorithm is fairly - robust against the loss of ACKs. - - Also the DSACK option [RFC2883] can be used to detect a posteriori - whether a TCP sender has entered loss recovery unnecessarily [BA02]. - However, the first ACK carrying a DSACK option usually arrives at a - TCP sender only after loss recovery has already terminated. Thus, - the DSACK option cannot be used to eliminate the retransmission - ambiguity. Consequently, it cannot be used to avoid the mentioned - unnecessary go-back-N retransmits. Moreover, a DSACK-based detection - algorithm is less robust against ACK losses. A recent proposal based - on neither the TCP timestamps nor the DSACK option does not have the - limitation of DSACK-based schemes, but only addresses the case of - spurious timeouts [SK03]. - -2. Events that Falsely Trigger TCP Loss Recovery - - The following events may falsely trigger a TCP sender's loss recovery - and congestion control algorithms. This causes a so-called spurious - retransmit, and an unnecessary reduction of the TCP sender's - congestion window and slow start threshold [RFC2581]. - - - Spurious timeout - - - Packet reordering - - - Packet duplication - - A spurious timeout is a timeout that would not have occurred had the - sender "waited longer". This may be caused by increased delay that - suddenly occurs in the data and/or the ACK path. That in turn might - cause an acceptable ACK to arrive too late, i.e., only after a TCP - sender's retransmission timer has expired. For the purpose of - specifying the algorithm in Section 3, we define this case as SPUR_TO - (equal 1). - - Note: There is another case where a timeout would not have - occurred had the sender "waited longer": the retransmission timer - expires, and afterwards the TCP sender receives the duplicate ACK - - - -Ludwig & Meyer Experimental [Page 3] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - that would have triggered a fast retransmit of the oldest - outstanding segment. We call this a 'fast timeout', since in - competition with the fast retransmit algorithm the timeout was - faster. However, a fast timeout is not spurious since apparently - a segment was in fact lost, i.e., loss recovery was initiated - rightfully. In this document, we do not consider fast timeouts. - - Packet reordering in the network may occur because IP [RFC791] does - not guarantee in-order delivery of packets. Additionally, a TCP - receiver generates a duplicate ACK for each segment that arrives - out-of-order. This results in a spurious fast retransmit if three or - more data segments arrive out-of-order at a TCP receiver, and at - least three of the resulting duplicate ACKs arrive at the TCP sender. - This assumes that the duplicate acknowledgement threshold is set to - three as defined in [RFC2581]. - - Packet duplication may occur because a receiving IP does not (cannot) - remove packets that have been duplicated in the network. A TCP - receiver in turn also generates a duplicate ACK for each duplicate - segment. As with packet reordering, this results in a spurious fast - retransmit if duplication of data segments or ACKs results in three - or more duplicate ACKs to arrive at a TCP sender. Again, this - assumes that the duplicate acknowledgement threshold is set to three. - - The negative impact on TCP performance caused by packet reordering - and packet duplication is commonly the same: a single spurious - retransmit (the fast retransmit), and the unnecessary halving of a - TCP sender's congestion window as a result of the subsequent fast - recovery phase [RFC2581]. - - The negative impact on TCP performance caused by a spurious timeout - is more severe. First, the timeout event itself causes a single - spurious retransmit, and unnecessarily forces a TCP sender into slow - start [RFC2581]. Then, as the connection progresses, a chain - reaction gets triggered that further decreases TCP's performance. - Since the timeout was spurious, at least some ACKs for original - transmits typically arrive at the TCP sender before the ACK for the - retransmit arrives. (This is unless severe packet reordering - coincided with the spurious timeout in such a way that the ACK for - the retransmit is the first acceptable ACK to arrive at the TCP - sender.) Those ACKs for original transmits then trigger an implicit - go-back-N loss recovery at the TCP sender [LK00]. Assuming that none - of the outstanding segments and none of the corresponding ACKs were - lost, all outstanding segments get retransmitted unnecessarily. In - fact, during this phase, a TCP sender violates the packet - conservation principle [Jac88]. This is because the unnecessary go- - back-N retransmits are sent during slow start. Thus, for each packet - that leaves the network and that belongs to the first half of the - - - -Ludwig & Meyer Experimental [Page 4] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - original flight, two useless retransmits are sent into the network. - In addition, some TCPs suffer from a spurious fast retransmit. This - is because the unnecessary go-back-N retransmits arrive as duplicates - at the TCP receiver, which in turn triggers a series of duplicate - ACKs. Note that this last spurious fast retransmit could be avoided - with the careful variant of 'bugfix' [RFC2582]. - - More detailed explanations, including TCP trace plots that visualize - the effects of spurious timeouts and packet reordering, can be found - in the original proposal [LK00]. - -3. The Eifel Detection Algorithm - -3.1 The Idea - - The goal of the Eifel detection algorithm is to allow a TCP sender to - detect a posteriori whether it has entered loss recovery - unnecessarily. Furthermore, the TCP sender should be able to make - this decision upon the first acceptable ACK that arrives after the - timeout-based retransmit or the fast retransmit has been sent. This - in turn requires extra information in ACKs by which the TCP sender - can unambiguously distinguish whether that first acceptable ACK was - sent in response to the original transmit or the retransmit. Such - extra information is provided by the TCP Timestamps option [RFC1323]. - Generally speaking, timestamps are monotonously increasing "serial - numbers" added into every segment that are then echoed within the - corresponding ACKs. This is exploited by the Eifel detection - algorithm in the following way. - - Given that timestamps are enabled for a connection, a TCP sender - always stores the timestamp of the retransmit sent in the beginning - of loss recovery, i.e., the timestamp of the timeout-based retransmit - or the fast retransmit. If the timestamp of the first acceptable - ACK, that arrives after the retransmit was sent, is smaller then the - stored timestamp of that retransmit, then that ACK must have been - sent in response to an original transmit. Hence, the TCP sender must - have entered loss recovery unnecessarily. - - The fact that the Eifel detection algorithm decides upon the first - acceptable ACK is crucial to allow future response algorithms to - avoid the unnecessary go-back-N retransmits that typically occur - after a spurious timeout. Also, if loss recovery was entered - unnecessarily, a window worth of ACKs are outstanding that all carry - a timestamp that is smaller than the stored timestamp of the - retransmit. The arrival of any one of those ACKs is sufficient for - the Eifel detection algorithm to work. Hence, the solution is fairly - - - - - -Ludwig & Meyer Experimental [Page 5] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - robust against ACK losses. Even the ACK sent in response to the - retransmit, i.e., the one that carries the stored timestamp, may get - lost without compromising the algorithm. - -3.2 The Algorithm - - Given that the TCP Timestamps option [RFC1323] is enabled for a - connection, a TCP sender MAY use the Eifel detection algorithm as - defined in this subsection. - - If the Eifel detection algorithm is used, the following steps MUST be - taken by a TCP sender, but only upon initiation of loss recovery, - i.e., when either the timeout-based retransmit or the fast retransmit - is sent. The Eifel detection algorithm MUST NOT be reinitiated after - loss recovery has already started. In particular, it must not be - reinitiated upon subsequent timeouts for the same segment, and not - upon retransmitting segments other than the oldest outstanding - segment, e.g., during selective loss recovery. - - (1) Set a "SpuriousRecovery" variable to FALSE (equal 0). - - (2) Set a "RetransmitTS" variable to the value of the - Timestamp Value field of the Timestamps option included in - the retransmit sent when loss recovery is initiated. A - TCP sender must ensure that RetransmitTS does not get - overwritten as loss recovery progresses, e.g., in case of - a second timeout and subsequent second retransmit of the - same octet. - - (3) Wait for the arrival of an acceptable ACK. When an - acceptable ACK has arrived, proceed to step (4). - - (4) If the value of the Timestamp Echo Reply field of the - acceptable ACK's Timestamps option is smaller than the - value of RetransmitTS, then proceed to step (5), - - else proceed to step (DONE). - - (5) If the acceptable ACK carries a DSACK option [RFC2883], - then proceed to step (DONE), - - else if during the lifetime of the TCP connection the TCP - sender has previously received an ACK with a DSACK option, - or the acceptable ACK does not acknowledge all outstanding - data, then proceed to step (6), - - else proceed to step (DONE). - - - - -Ludwig & Meyer Experimental [Page 6] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - (6) If the loss recovery has been initiated with a timeout- - based retransmit, then set - SpuriousRecovery <- SPUR_TO (equal 1), - - else set - SpuriousRecovery <- dupacks+1 - - (RESP) Do nothing (Placeholder for a response algorithm). - - (DONE) No further processing. - - The comparison "smaller than" in step (4) is conservative. In - theory, if the timestamp clock is slow or the network is fast, - RetransmitTS could at most be equal to the timestamp echoed by an ACK - sent in response to an original transmit. In that case, it is - assumed that the loss recovery was not falsely triggered. - - Note that the condition "if during the lifetime of the TCP connection - the TCP sender has previously received an ACK with a DSACK option" in - step (5) would be true in case the TCP receiver would signal in the - SYN that it is DSACK-enabled. But unfortunately, this is not - required by [RFC2883]. - -3.3 A Corner Case: "Timeout due to loss of all ACKs" (step 5) - - Even though the oldest outstanding segment arrived at a TCP receiver, - the TCP sender is forced into a timeout if all ACKs are lost. - Although the resulting retransmit is unnecessary, such a timeout is - unavoidable. It should therefore not be considered spurious. - Moreover, the subsequent reduction of the congestion window is an - appropriate response to the potentially heavy congestion in the ACK - path. The original proposal [LK00] does not handle this case well. - It effectively disables this implicit form of congestion control for - the ACK path, which otherwise does not exist in TCP. This problem is - fixed by step (5) of the Eifel detection algorithm as explained in - the remainder of this section. - - If all ACKs are lost while the oldest outstanding segment arrived at - the TCP receiver, the retransmit arrives as a duplicate. In response - to duplicates, RFC 1323 mandates that the timestamp of the last - segment that arrived in-sequence should be echoed. That timestamp is - carried by the first acceptable ACK that arrives at the TCP sender - after loss recovery was entered, and is commonly smaller than the - timestamp carried by the retransmit. Consequently, the Eifel - detection algorithm misinterprets such a timeout as being spurious, - unless the TCP receiver is DSACK-enabled [RFC2883]. In that case, - the acceptable ACK carries a DSACK option, and the Eifel algorithm is - terminated through the first part of step (5). - - - -Ludwig & Meyer Experimental [Page 7] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - Note: Not all TCP implementations strictly follow RFC 1323. In - response to a duplicate data segment, some TCP receivers echo the - timestamp of the duplicate. With such TCP receivers, the corner - case discussed in this section does not apply. The timestamp - carried by the retransmit would be echoed in the first acceptable - ACK, and the Eifel detection algorithm would be terminated through - step (4). Thus, even though all ACKs were lost and independent of - whether the DSACK option was enabled for a connection, the Eifel - detection algorithm would have no effect. - - With TCP receivers that are not DSACK-enabled, disabling the - mentioned implicit congestion control for the ACK path is not a - problem as long as data segments are lost, in addition to the entire - flight of ACKs. The Eifel detection algorithm misinterprets such a - timeout as being spurious, and the Eifel response algorithm would - reverse the congestion control state. Still, the TCP sender would - respond to congestion (in the data path) as soon as it finds out - about the first loss in the outstanding flight. I.e., the TCP sender - would still halve its congestion window for that flight of packets. - If no data segment is lost while the entire flight of ACKs is lost, - the first acceptable ACK that arrives at the TCP sender after loss - recovery was entered acknowledges all outstanding data. In that - case, the Eifel algorithm is terminated through the second part of - step (5). - - Note that there is little concern about violating the packet - conservation principle when entering slow start after an unavoidable - timeout caused by the loss of an entire flight of ACKs, i.e., when - the Eifel detection algorithm was terminated through step (5). This - is because in that case, the acceptable ACK corresponds to the - retransmit, which is a strong indication that the pipe has drained - entirely, i.e., that no more original transmits are in the network. - This is different with spurious timeouts as discussed in Section 2. - -3.4 Protecting Against Misbehaving TCP Receivers (the Safe Variant) - - A TCP receiver can easily make a genuine retransmit appear to the TCP - sender as a spurious retransmit by forging echoed timestamps. This - may pose a security concern. - - Fortunately, there is a way to modify the Eifel detection algorithm - in a way that makes it robust against lying TCP receivers. The idea - is to use timestamps as a segment's "secret" that a TCP receiver only - gets to know if it receives the segment. Conversely, a TCP receiver - will not know the timestamp of a segment that was lost. Hence, to - "prove" that it received the original transmit of a segment that a - TCP sender retransmitted, the TCP receiver would need to return the - timestamp of that original transmit. The Eifel detection algorithm - - - -Ludwig & Meyer Experimental [Page 8] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - could then be modified to only decide that loss recovery has been - unnecessarily entered if the first acceptable ACK echoes the - timestamp of the original transmit. - - Hence, implementers may choose to implement the algorithm with the - following modifications. - - Step (2) is replaced with step (2'): - - (2') Set a "RetransmitTS" variable to the value of the - Timestamp Value field of the Timestamps option that was - included in the original transmit corresponding to the - retransmit. Note: This step requires that the TCP sender - stores the timestamps of all outstanding original - transmits. - - Step (4) is replaced with step (4'): - - (4') If the value of the Timestamp Echo Reply field of the - acceptable ACK's Timestamps option is equal to the value - of the variable RetransmitTS, then proceed to step (5), - - else proceed to step (DONE). - - These modifications come at a cost: the modified algorithm is fairly - sensitive against ACK losses since it relies on the arrival of the - acceptable ACK that corresponds to the original transmit. - - Note: The first acceptable ACK that arrives after loss recovery - has been unnecessarily entered should echo the timestamp of the - original transmit. This assumes that the ACK corresponding to the - original transmit was not lost, that that ACK was not reordered in - the network, and that the TCP receiver does not forge timestamps - but complies with RFC 1323. In case of a spurious fast - retransmit, this is implied by the rules for generating ACKs for - data segments that fill in all or part of a gap in the sequence - space (see section 4.2 of [RFC2581]) and by the rules for echoing - timestamps in that case (see rule (C) in section 3.4 of - [RFC1323]). In case of a spurious timeout, it is likely that the - delay that has caused the spurious timeout has also caused the TCP - receiver's delayed ACK timer [RFC1122] to expire before the - original transmit arrives. Also, in this case the rules for - generating ACKs and the rules for echoing timestamps (see rule (A) - in section 3.4 of [RFC1323]) ensure that the original transmit's - timestamp is echoed. - - - - - - -Ludwig & Meyer Experimental [Page 9] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - A remaining problem is that a TCP receiver might guess a lost - segment's timestamp from observing the timestamps of recently - received segments. For example, if segment N was lost while segment - N-1 and N+1 have arrived, a TCP receiver could guess the timestamp - that lies in the middle of the timestamps of segments N-1 and N+1, - and echo it in the ACK sent in response to the retransmit of segment - N. Especially if the TCP sender implements timestamps with a coarse - granularity, a misbehaving TCP receiver is likely to be successful - with such an approach. In fact, with the 500 ms granularity - suggested in [WS95], it even becomes quite likely that the timestamps - of segments N-1, N, N+1 are identical. - - One way to reduce this risk is to implement fine grained timestamps. - Note that the granularity of the timestamps is independent of the - granularity of the retransmission timer. For example, some TCP - implementations run a timestamp clock that ticks every millisecond. - This should make it more difficult for a TCP receiver to guess the - timestamp of a lost segment. Alternatively, it might be possible to - combine the timestamps with a nonce, as is done for the Explicit - Congestion Notification (ECN) [RFC3168]. One would need to take - care, though, that the timestamps of consecutive segments remain - monotonously increasing and do not interfere with the RTT timing - defined in [RFC1323]. - -4. IPR Considerations - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights at http://www.ietf.org/ipr. - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - - - - - - -Ludwig & Meyer Experimental [Page 10] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - -5. Security Considerations - - There do not seem to be any security considerations associated with - the Eifel detection algorithm. This is because the Eifel detection - algorithm does not alter the existing protocol state at a TCP sender. - Note that the Eifel detection algorithm only requires changes to the - implementation of a TCP sender. - - Moreover, a variant of the Eifel detection algorithm has been - proposed in Section 3.4 that makes it robust against lying TCP - receivers. This may become relevant when the Eifel detection - algorithm is combined with a response algorithm such as the Eifel - response algorithm [LG03]. - -Acknowledgments - - Many thanks to Keith Sklower, Randy Katz, Stephan Baucke, Sally - Floyd, Vern Paxson, Mark Allman, Ethan Blanton, Andrei Gurtov, Pasi - Sarolahti, and Alexey Kuznetsov for useful discussions that - contributed to this work. - -Normative References - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2883] Floyd, S., Mahdavi, J., Mathis, M., Podolsky, M. and A. - Romanow, "An Extension to the Selective Acknowledgement - (SACK) Option for TCP", RFC 2883, July 2000. - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions for - High Performance", RFC 1323, May 1992. - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, October 1996. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - - - - - - - - - -Ludwig & Meyer Experimental [Page 11] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - -Informative References - - [BA02] Blanton, E. and M. Allman, "Using TCP DSACKs and SCTP - Duplicate TSNs to Detect Spurious Retransmissions", Work in - Progress. - - [RFC1122] Braden, R., "Requirements for Internet Hosts - - Communication Layers", STD 3, RFC 1122, October 1989. - - [RFC2582] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [Gu01] Gurtov, A., "Effect of Delays on TCP Performance", In - Proceedings of IFIP Personal Wireless Communications, - August 2001. - - [RFC3481] Inamura, H., Montenegro, G., Ludwig, R., Gurtov, A. and F. - Khafizov, "TCP over Second (2.5G) and Third (3G) Generation - Wireless Networks", RFC 3481, February 2003. - - [Jac88] Jacobson, V., "Congestion Avoidance and Control", In - Proceedings of ACM SIGCOMM 88. - - [KP87] Karn, P. and C. Partridge, "Improving Round-Trip Time - Estimates in Reliable Transport Protocols", In Proceedings - of ACM SIGCOMM 87. - - [LK00] Ludwig, R. and R. H. Katz, "The Eifel Algorithm: Making TCP - Robust Against Spurious Retransmissions", ACM Computer - Communication Review, Vol. 30, No. 1, January 2000. - - [LG03] Ludwig, R. and A. Gurtov, "The Eifel Response Algorithm for - TCP", Work in Progress. - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, September - 1981. - - [RFC3168] Ramakrishnan, K., Floyd, S. and D. Black, "The Addition of - Explicit Congestion Notification (ECN) to IP", RFC 3168, - September 2001. - - [SK03] Sarolahti, P. and M. Kojo, "F-RTO: A TCP RTO Recovery - Algorithm for Avoiding Unnecessary Retransmissions", Work - in Progress. - - - - -Ludwig & Meyer Experimental [Page 12] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - - [WS95] Wright, G. R. and W. R. Stevens, "TCP/IP Illustrated, - Volume 2 (The Implementation)", Addison Wesley, January - 1995. - - [Zh86] Zhang, L., "Why TCP Timers Don't Work Well", In Proceedings - of ACM SIGCOMM 86. - -Authors' Addresses - - Reiner Ludwig - Ericsson Research - Ericsson Allee 1 - 52134 Herzogenrath, Germany - - EMail: Reiner.Ludwig@eed.ericsson.se - - - Michael Meyer - Ericsson Research - Ericsson Allee 1 - 52134 Herzogenrath, Germany - - EMail: Michael.Meyer@eed.ericsson.se - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ludwig & Meyer Experimental [Page 13] - -RFC 3522 The Eifel Detection Algorithm for TCP April 2003 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Ludwig & Meyer Experimental [Page 14] - diff --git a/ext/picotcp/RFC/rfc3540.txt b/ext/picotcp/RFC/rfc3540.txt deleted file mode 100644 index f781c50..0000000 --- a/ext/picotcp/RFC/rfc3540.txt +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - -Network Working Group N. Spring -Request for Comments: 3540 D. Wetherall -Category: Experimental D. Ely - University of Washington - June 2003 - - - Robust Explicit Congestion Notification (ECN) - Signaling with Nonces - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - This note describes the Explicit Congestion Notification (ECN)-nonce, - an optional addition to ECN that protects against accidental or - malicious concealment of marked packets from the TCP sender. It - improves the robustness of congestion control by preventing receivers - from exploiting ECN to gain an unfair share of network bandwidth. - The ECN-nonce uses the two ECN-Capable Transport (ECT)codepoints in - the ECN field of the IP header, and requires a flag in the TCP - header. It is computationally efficient for both routers and hosts. - -1. Introduction - - Statement of Intent - - This specification describes an optional addition to Explicit - Congestion Notification [RFC3168] improving its robustness against - malicious or accidental concealment of marked packets. It has not - been deployed widely. One goal of publication as an Experimental - RFC is to be prudent, and encourage use and deployment prior to - publication in the standards track. Another consideration is to - give time for firewall developers to recognize and accept the - pattern presented by the nonce. It is the intent of the Transport - Area Working Group to re-submit this specification as an IETF - Proposed Standard in the future after more experience has been - gained. - - - - -Spring, et. al. Experimental [Page 1] - -RFC 3540 Robust ECN Signaling June 2003 - - - The correct operation of ECN requires the cooperation of the receiver - to return Congestion Experienced signals to the sender, but the - protocol lacks a mechanism to enforce this cooperation. This raises - the possibility that an unscrupulous or poorly implemented receiver - could always clear ECN-Echo and simply not return congestion signals - to the sender. This would give the receiver a performance advantage - at the expense of competing connections that behave properly. More - generally, any device along the path (NAT box, firewall, QOS - bandwidth shapers, and so forth) could remove congestion marks with - impunity. - - The above behaviors may or may not constitute a threat to the - operation of congestion control in the Internet. However, given the - central role of congestion control, it is prudent to design the ECN - signaling loop to be robust against as many threats as possible. In - this way, ECN can provide a clear incentive for improvement over the - prior state-of-the-art without potential incentives for abuse. The - ECN-nonce is a simple, efficient mechanism to eliminate the potential - abuse of ECN. - - The ECN-nonce enables the sender to verify the correct behavior of - the ECN receiver and that there is no other interference that - conceals marked (or dropped) packets in the signaling path. The ECN- - nonce protects against both implementation errors and deliberate - abuse. The ECN-nonce: - - - catches a misbehaving receiver with a high probability, and never - implicates an innocent receiver. - - - does not change other aspects of ECN, nor does it reduce the - benefits of ECN for behaving receivers. - - - is cheap in both per-packet overhead (one TCP header flag) and - processing requirements. - - - is simple and, to the best of our knowledge, not prone to other - attacks. - - We also note that use of the ECN-nonce has two additional benefits, - even when only drop-tail routers are used. First, packet drops - cannot be concealed from the sender. Second, it prevents optimistic - acknowledgements [Savage], in which TCP segments are acknowledged - before they have been received. These benefits also serve to - increase the robustness of congestion control from attacks. We do - not elaborate on these benefits in this document. - - The rest of this document describes the ECN-nonce. We present an - overview followed by detailed behavior at senders and receivers. - - - -Spring, et. al. Experimental [Page 2] - -RFC 3540 Robust ECN Signaling June 2003 - - - The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, - SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this - document, are to be interpreted as described in [RFC2119]. - -2. Overview - - The ECN-nonce builds on the existing ECN-Echo and Congestion Window - Reduced (CWR) signaling mechanism. Familiarity with ECN [ECN] is - assumed. For simplicity, we describe the ECN-nonce in one direction - only, though it is run in both directions in parallel. - - The ECN protocol for TCP remains unchanged, except for the definition - of a new field in the TCP header. As in [RFC3168], ECT(0) or ECT(1) - (ECN-Capable Transport) is set in the ECN field of the IP header on - outgoing packets. Congested routers change this field to CE - (Congestion Experienced). When TCP receivers notice CE, the ECE - (ECN-Echo) flag is set in subsequent acknowledgements until receiving - a CWR flag. The CWR flag is sent on new data whenever the sender - reacts to congestion. - - The ECN-nonce adds to this protocol, and enables the receiver to - demonstrate to the sender that segments being acknowledged were - received unmarked. A random one-bit value (a nonce) is encoded in - the two ECT codepoints. The one-bit sum of these nonces is returned - in a TCP header flag, the nonce sum (NS) bit. Packet marking erases - the nonce value in the ECT codepoints because CE overwrites both ECN - IP header bits. Since each nonce is required to calculate the sum, - the correct nonce sum implies receipt of only unmarked packets. Not - only are receivers prevented from concealing marked packets, middle- - boxes along the network path cannot unmark a packet without - successfully guessing the value of the original nonce. - - The sender can verify the nonce sum returned by the receiver to - ensure that congestion indications in the form of marked (or dropped) - packets are not being concealed. Because the nonce sum is only one - bit long, senders have a 50-50 chance of catching a lying receiver - whenever an acknowledgement conceals a mark. Because each - acknowledgement is an independent trial, cheaters will be caught - quickly if there are repeated congestion signals. - - The following paragraphs describe aspects of the ECN-nonce protocol - in greater detail. - - - - - - - - - -Spring, et. al. Experimental [Page 3] - -RFC 3540 Robust ECN Signaling June 2003 - - - Each acknowledgement carries a nonce sum, which is the one bit sum - (exclusive-or, or parity) of nonces over the byte range represented - by the acknowledgement. The sum is used because not every packet is - acknowledged individually, nor are packets acknowledged reliably. If - a sum were not used, the nonce in an unmarked packet could be echoed - to prove to the sender that the individual packet arrived unmarked. - However, since these acks are not reliably delivered, the sender - could not distinguish a lost ACK from one that was never sent in - order to conceal a marked packet. The nonce sum prevents the - receiver from concealing individual marked packets by not - acknowledging them. Because the nonce and nonce sum are both one bit - quantities, the sum is no easier to guess than the individual nonces. - We show the nonce sum calculation below in Figure 1. - - Sender Receiver - initial sum = 1 - -- 1:4 ECT(0) --> NS = 1 + 0(1:4) = 1(:4) - <- ACK 4, NS=1 --- - -- 4:8 ECT(1) --> NS = 1(:4) + 1(4:8) = 0(:8) - <- ACK 8, NS=0 --- - -- 8:12 ECT(1) -> NS = 0(:8) + 1(8:12) = 1(:12) - <- ACK 12, NS=1 -- - -- 12:16 ECT(1) -> NS = 1(:12) + 1(12:16) = 0(:16) - <- ACK 16, NS=0 -- - - Figure 1: The calculation of nonce sums at the receiver. - - After congestion has occurred and packets have been marked or lost, - resynchronization of the sender and receiver nonce sums is needed. - When packets are marked, the nonce is cleared, and the sum of the - nonces at the receiver will no longer match the sum at the sender. - Once nonces have been lost, the difference between sender and - receiver nonce sums is constant until there is further loss. This - means that it is possible to resynchronize the sender and receiver - after congestion by having the sender set its nonce sum to that of - the receiver. Because congestion indications do not need to be - conveyed more frequently than once per round trip, the sender - suspends checking while the CWR signal is being delivered and resets - its nonce sum to the receiver's when new data is acknowledged. This - has the benefit that the receiver is not explicitly involved in the - re-synchronization process. The resynchronization process is shown - in Figure 2 below. Note that the nonce sum returned in ACK 12 (NS=0) - differs from that in the previous example (NS=1), and it continues to - differ for ACK 16. - - - - - - - -Spring, et. al. Experimental [Page 4] - -RFC 3540 Robust ECN Signaling June 2003 - - - Sender Receiver - initial sum = 1 - -- 1:4 ECT(0) -> NS = 1 + 0(1:4) = 1(:4) - <- ACK 4, NS=1 -- - -- 4:8 ECT(1) -> CE -> NS = 1(:4) + ?(4:8) = 1(:8) - <- ACK 8, ECE NS=1 -- - -- 8:12 ECT(1), CWR -> NS = 1(:8) + 1(8:12) = 0(:12) - <- ACK 12, NS=0 -- - -- 12:16 ECT(1) -> NS = 0(:12) + 1(12:16) = 1(:16) - <- ACK 16, NS=1 -- - - Figure 2: The calculation of nonce sums at the receiver when a - packet (4:8) is marked. The receiver may calculate the wrong - nonce sum when the original nonce information is lost after a - packet is marked. - - Third, we need to reconcile that nonces are sent with packets but - acknowledgements cover byte ranges. Acknowledged byte boundaries - need not match the transmitted boundaries, and information can be - retransmitted in packets with different byte boundaries. We discuss - the first issue, how a receiver sets a nonce when acknowledging part - of a segment, in Section 6.1. The second question, what nonce to send - when retransmitting smaller segments as a large segment, has a simple - answer: ECN is disabled for retransmissions, so can carry no nonce. - Because retransmissions are associated with congestion events, nonce - checking is suspended until after CWR is acknowledged and the - congestion event is over. - - The next sections describe the detailed behavior of senders, routers - and receivers, starting with sender transmit behavior, then around - the ECN signaling loop, and finish with sender acknowledgement - processing. - -3. Sender Behavior (Transmit) - - Senders manage CWR and ECN-Echo as before. In addition, they must - place nonces on packets as they are transmitted and check the - validity of the nonce sums in acknowledgments as they are received. - This section describes the transmit process. - - To place a one bit nonce value on every ECN-capable IP packet, the - sender uses the two ECT codepoints: ECT(0) represents a nonce of 0, - and ECT(1) a nonce of 1. As in ECN, retransmissions are not ECN- - capable, so carry no nonce. - - The sender maintains a mapping from each packet's end sequence number - to the expected nonce sum (not the nonce placed in the original - transmission) in the acknowledgement bearing that sequence number. - - - -Spring, et. al. Experimental [Page 5] - -RFC 3540 Robust ECN Signaling June 2003 - - -4. Router Behavior - - Routers behave as specified in [RFC3168]. By marking packets to - signal congestion, the original value of the nonce, in ECT(0) or - ECT(1), is removed. Neither the receiver nor any other party can - unmark the packet without successfully guessing the value of the - original nonce. - -5. Receiver Behavior (Receive and Transmit) - - ECN-nonce receivers maintain the nonce sum as in-order packets arrive - and return the current nonce sum in each acknowledgement. Receiver - behavior is otherwise unchanged from [RFC3168]. Returning the nonce - sum is optional, but recommended, as senders are allowed to - discontinue sending ECN-capable packets to receivers that do not - support the ECN-nonce. - - As packets are removed from the queue of out-of-order packets to be - acknowledged, the nonce is recovered from the IP header. The nonce - is added to the current nonce sum as the acknowledgement sequence - number is advanced for the recent packet. - - In the case of marked packets, one or more nonce values may be - unknown to the receiver. In this case the missing nonce values are - ignored when calculating the sum (or equivalently a value of zero is - assumed) and ECN-Echo will be set to signal congestion to the sender. - - Returning the nonce sum corresponding to a given acknowledgement is - straightforward. It is carried in a single "NS" (Nonce Sum) bit in - the TCP header. This bit is adjacent to the CWR and ECN-Echo bits, - set as Bit 7 in byte 13 of the TCP header, as shown below: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - | | | N | C | E | U | A | P | R | S | F | - | Header Length | Reserved | S | W | C | R | C | S | S | Y | I | - | | | | R | E | G | K | H | T | N | N | - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - - Figure 3: The new definition of bytes 13 and 14 of the TCP Header. - - The initial nonce sum is 1, and is included in the SYN/ACK and ACK of - the three way TCP handshake. This allows the other endpoint to infer - nonce support, but is not a negotiation, in that the receiver of the - SYN/ACK need not check if NS is set to decide whether to set NS in - the subsequent ACK. - - - - - -Spring, et. al. Experimental [Page 6] - -RFC 3540 Robust ECN Signaling June 2003 - - -6. Sender Behavior (Receive) - - This section completes the description of sender behavior by - describing how senders check the validity of the nonce sums. - - The nonce sum is checked when an acknowledgement of new data is - received, except during congestion recovery when additional ECN-Echo - signals would be ignored. Checking consists of comparing the correct - nonce sum stored in a buffer to that carried in the acknowledgement, - with a correction described in the following subsection. - - If ECN-Echo is not set, the receiver claims to have received no - marked packets, and can therefore compute and return the correct - nonce sum. To conceal a mark, the receiver must successfully guess - the sum of the nonces that it did not receive, because at least one - packet was marked and the corresponding nonce was erased. Provided - the individual nonces are equally likely to be 0 or 1, their sum is - equally likely to be 0 or 1. In other words, any guess is equally - likely to be wrong and has a 50-50 chance of being caught by the - sender. Because each new acknowledgement is an independent trial, a - cheating receiver is likely to be caught after a small number of - lies. - - If ECN-Echo is set, the receiver is sending a congestion signal and - it is not necessary to check the nonce sum. The congestion window - will be halved, CWR will be set on the next packet with new data - sent, and ECN-Echo will be cleared once the CWR signal is received, - as in [RFC3168]. During this recovery process, the sum may be - incorrect because one or more nonces were not received. This does - not matter during recovery, because TCP invokes congestion mechanisms - at most once per RTT, whether there are one or more losses during - that period. - -6.1. Resynchronization After Loss or Mark - - After recovery, it is necessary to re-synchronize the sender and - receiver nonce sums so that further acknowledgments can be checked. - When the receiver's sum is incorrect, it will remain incorrect until - further loss. - - This leads to a simple re-synchronization mechanism where the sender - resets its nonce sum to that of the receiver when it receives an - acknowledgment for new data sent after the congestion window was - reduced. When responding to explicit congestion signals, this will - be the first acknowledgement without the ECN-Echo flag set: the - acknowledgement of the packet containing the CWR flag. - - - - - -Spring, et. al. Experimental [Page 7] - -RFC 3540 Robust ECN Signaling June 2003 - - - Sender Receiver - initial sum = 1 - -- 1:4 ECT(0) -> NS = 1 + 0(1:4) = 1(:4) - <- ACK 4, NS=1 -- - -- 4:8 ECT(1) -> LOST - -- 8:12 ECT(1) -> nonce sum calculation deferred - until in-order data received - <- ACK 4, NS=0 -- - -- 12:16 ECT(1) -> nonce sum calculation deferred - <- ACK 4, NS=0 -- - -- 4:8 retransmit -> NS = 1(:4) + ?(4:8) + - 1(8:12) + 1(12:16) = 1(:16) - <- ACK 16, NS=1 -- - -- 16:20 ECT(1) CWR -> - <- ACK 20, NS=0 -- NS = 1(:16) + 1(16:20) = 0(:20) - - Figure 4: The calculation of nonce sums at the receiver when a - packet is lost, and resynchronization after loss. The nonce sum - is not changed until the cumulative acknowledgement is advanced. - - In practice, resynchronization can be accomplished by storing a bit - that has the value one if the expected nonce sum stored by the sender - and the received nonce sum in the acknowledgement of CWR differ, and - zero otherwise. This synchronization offset bit can then be used in - the comparison between expected nonce sum and received nonce sum. - - The sender should ignore the nonce sum returned on any - acknowledgements bearing the ECN-echo flag. - - When an acknowledgment covers only a portion of a segment, such as - when a middlebox resegments at the TCP layer instead of fragmenting - IP packets, the sender should accept the nonce sum expected at the - next segment boundary. In other words, an acknowledgement covering - part of an original segment will include the nonce sum expected when - the entire segment is acknowledged. - - Finally, in ECN, senders can choose not to indicate ECN capability on - some packets for any reason. An ECN-nonce sender must resynchronize - after sending such ECN-incapable packets, as though a CWR had been - sent with the first new data after the ECN-incapable packets. The - sender loses protection for any unacknowledged packets until - resynchronization occurs. - - - - - - - - - -Spring, et. al. Experimental [Page 8] - -RFC 3540 Robust ECN Signaling June 2003 - - -6.2. Sender Behavior - Incorrect Nonce Received - - The sender's response to an incorrect nonce is a matter of policy. - It is separate from the checking mechanism and does not need to be - handled uniformly by senders. Further, checking received nonce sums - at all is optional, and may be disabled. - - If the receiver has never sent a non-zero nonce sum, the sender can - infer that the receiver does not understand the nonce, and rate limit - the connection, place it in a lower-priority queue, or cease setting - ECT in outgoing segments. - - If the received nonce sum has been set in a previous acknowledgement, - the sender might infer that a network device has interfered with - correct ECN signaling between ECN-nonce supporting endpoints. The - minimum response to an incorrect nonce is the same as the response to - a received ECE. However, to compensate for hidden congestion - signals, the sender might reduce the congestion window to one segment - and cease setting ECT in outgoing segments. An incorrect nonce sum - is a sign of misbehavior or error between ECN-nonce supporting - endpoints. - -6.2.1. Using the ECN-nonce to Protect Against Other Misbehaviors - - The ECN-nonce can provide robustness beyond checking that marked - packets are signaled to the sender. It also ensures that dropped - packets cannot be concealed from the sender (because their nonces - have been lost). Drops could potentially be concealed by a faulty - TCP implementation, certain attacks, or even a hypothetical TCP - accelerator. Such an accelerator could gamble that it can either - successfully "fast start" to a preset bandwidth quickly, retry with - another connection, or provide reliability at the application level. - If robustness against these faults is also desired, then the ECN- - nonce should not be disabled. Instead, reducing the congestion - window to one, or using a low-priority queue, would penalize faulty - operation while providing continued checking. - - The ECN-nonce can also detect misbehavior in Eifel [Eifel], a - recently proposed mechanism for removing the retransmission ambiguity - to improve TCP performance. A misbehaving receiver might claim to - have received only original transmissions to convince the sender to - undo congestion actions. Since retransmissions are sent without ECT, - and thus no nonce, returning the correct nonce sum confirms that only - original transmissions were received. - - - - - - - -Spring, et. al. Experimental [Page 9] - -RFC 3540 Robust ECN Signaling June 2003 - - -7. Interactions - -7.1. Path MTU Discovery - - As described in RFC3168, use of the Don't Fragment bit with ECN is - recommended. Receivers that receive unmarked fragments can - reconstruct the original nonce to conceal a marked fragment. The - ECN-nonce cannot protect against misbehaving receivers that conceal - marked fragments, so some protection is lost in situations where Path - MTU discovery is disabled. - - When responding to a small path MTU, the sender will retransmit a - smaller frame in place of a larger one. Since these smaller packets - are retransmissions, they will be ECN-incapable and bear no nonce. - The sender should resynchronize on the first newly transmitted - packet. - -7.2. SACK - - Selective acknowledgements allow receivers to acknowledge out of - order segments as an optimization. It is not necessary to modify the - selective acknowledgment option to fit per-range nonce sums, because - SACKs cannot be used by a receiver to hide a congestion signal. The - nonce sum corresponds only to the data acknowledged by the cumulative - acknowledgement. - -7.3. IPv6 - - Although the IPv4 header is protected by a checksum, this is not the - case with IPv6, making undetected bit errors in the IPv6 header more - likely. Bit errors that compromise the integrity of the congestion - notification fields may cause an incorrect nonce to be received, and - an incorrect nonce sum to be returned. - -8. Security Considerations - - The random one-bit nonces need not be from a cryptographic-quality - pseudo-random number generator. A strong random number generator - would compromise performance. Consequently, the sequence of random - nonces should not be used for any other purpose. - - Conversely, the pseudo-random bit sequence should not be generated by - a linear feedback shift register [Schneier], or similar scheme that - would allow an adversary who has seen several previous bits to infer - the generation function and thus its future output. - - - - - - -Spring, et. al. Experimental [Page 10] - -RFC 3540 Robust ECN Signaling June 2003 - - - Although the ECN-nonce protects against concealment of congestion - signals and optimistic acknowledgement, it provides no additional - protection for the integrity of the connection. - -9. IANA Considerations - - The Nonce Sum (NS) is carried in a reserved TCP header bit that must - be allocated. This document describes the use of Bit 7, adjacent to - the other header bits used by ECN. - - The codepoint for the NS flag in the TCP header is specified by the - Standards Action of this RFC, as is required by RFC 2780. The IANA - has added the following to the registry for "TCP Header Flags": - - RFC 3540 defines bit 7 from the Reserved field to be used for the - Nonce Sum, as follows: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - | | | N | C | E | U | A | P | R | S | F | - | Header Length | Reserved | S | W | C | R | C | S | S | Y | I | - | | | | R | E | G | K | H | T | N | N | - +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - - TCP Header Flags - - Bit Name Reference - --- ---- --------- - 7 NS (Nonce Sum) [RFC 3540] - -10. Conclusion - - The ECN-nonce is a simple modification to the ECN signaling mechanism - that improves ECN's robustness by preventing receivers from - concealing marked (or dropped) packets. The intent of this work is - to help improve the robustness of congestion control in the Internet. - The modification retains the character and simplicity of existing ECN - signaling. It is also practical for deployment in the Internet. It - uses the ECT(0) and ECT(1) codepoints and one TCP header flag (as - well as CWR and ECN-Echo) and has simple processing rules. - - - - - - - - - - - -Spring, et. al. Experimental [Page 11] - -RFC 3540 Robust ECN Signaling June 2003 - - -11. References - - [ECN] "The ECN Web Page", URL - "http://www.icir.org/floyd/ecn.html". - - [RFC3168] Ramakrishnan, K., Floyd, S. and D. Black, "The addition of - explicit congestion notification (ECN) to IP", RFC 3168, - September 2001. - - [Eifel] R. Ludwig and R. Katz. The Eifel Algorithm: Making TCP - Robust Against Spurious Retransmissions. Computer - Communications Review, January, 2000. - - [B97] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [Savage] S. Savage, N. Cardwell, D. Wetherall, T. Anderson. TCP - congestion control with a misbehaving receiver. SIGCOMM - CCR, October 1999. - - [Schneier] Bruce Schneier. Applied Cryptography, 2nd ed., 1996 - -12. Acknowledgements - - This note grew out of research done by Stefan Savage, David Ely, - David Wetherall, Tom Anderson and Neil Spring. We are very grateful - for feedback and assistance from Sally Floyd. - -13. Authors' Addresses - - Neil Spring - EMail: nspring@cs.washington.edu - - - David Wetherall - Department of Computer Science and Engineering, Box 352350 - University of Washington - Seattle WA 98195-2350 - EMail: djw@cs.washington.edu - - - David Ely - Computer Science and Engineering, 352350 - University of Washington - Seattle, WA 98195-2350 - EMail: ely@cs.washington.edu - - - - - -Spring, et. al. Experimental [Page 12] - -RFC 3540 Robust ECN Signaling June 2003 - - -14. Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Spring, et. al. Experimental [Page 13] - diff --git a/ext/picotcp/RFC/rfc3562.txt b/ext/picotcp/RFC/rfc3562.txt deleted file mode 100644 index 7a23a5b..0000000 --- a/ext/picotcp/RFC/rfc3562.txt +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - -Network Working Group M. Leech -Request for Comments: 3562 Nortel Networks -Category:Informational July 2003 - - - Key Management Considerations for - the TCP MD5 Signature Option - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - The TCP MD5 Signature Option (RFC 2385), used predominantly by BGP, - has seen significant deployment in critical areas of Internet - infrastructure. The security of this option relies heavily on the - quality of the keying material used to compute the MD5 signature. - This document addresses the security requirements of that keying - material. - -1. Introduction - - The security of various cryptographic functions lies both in the - strength of the functions themselves against various forms of attack, - and also, perhaps more importantly, in the keying material that is - used with them. While theoretical attacks against the simple MAC - construction used in RFC 2385 are possible [MDXMAC], the number of - text-MAC pairs required to mount a forgery make it vastly more - probable that key-guessing is the main threat against RFC 2385. - - We show a quantitative approach to determining the security - requirements of keys used with [RFC2385], which tends to suggest the - following: - - o Key lengths SHOULD be between 12 and 24 bytes, with larger keys - having effectively zero additional computational costs when - compared to shorter keys. - - - - - - - -Leech Informational [Page 1] - -RFC 3562 Considerations for the TCP MD5 Signature Option July 2003 - - - o Key sharing SHOULD be limited so that keys aren't shared among - multiple BGP peering arrangements. - - o Keys SHOULD be changed at least every 90 days. - -1.1. Requirements Keywords - - The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", - and "MAY" that appear in this document are to be interpreted as - described in [RFC2119]. - -2. Performance assumptions - - The most recent performance study of MD5 that this author was able to - find was undertaken by J. Touch at ISI. The results of this study - were documented in [RFC1810]. The assumption is that Moores Law - applies to the data in the study, which at the time showed a - best-possible *software* performance for MD5 of 87Mbits/second. - Projecting this number forward to the ca 2002 timeframe of this - document, would suggest a number near 2.1Gbits/second. - - For purposes of simplification, we will assume that our key-guessing - attacker will attack short packets only. A likely minimal packet is - an ACK, with no data. This leads to having to compute the MD5 over - about 40 bytes of data, along with some reasonable maximum number of - key bytes. MD5 effectively pads its input to 512-bit boundaries (64 - bytes) (it's actually more complicated than that, but this - simplifying assumption will suffice for this analysis). That means - that a minimum MD5 "block" is 64 bytes, so for a ca 2002-scaled - software performance of 2.1Gbits/second, we get a single-CPU software - MD5 performance near 4.1e6 single-block MD5 operations per second. - - These numbers are, of course, assuming that any key-guessing attacker - is resource-constrained to a single CPU. In reality, distributed - cryptographic key-guessing attacks have been remarkably successful in - the recent past. - - It may be instructive to look at recent Internet worm infections, to - determine what the probable maximum number of hosts that could be - surreptitiously marshalled for a key-guessing attack against MD5. - CAIDA [CAIDA2001] has reported that the Code Red worm infected over - 350,000 Internet hosts in the first 14 hours of operation. It seems - reasonable to assume that a worm whose "payload" is a mechanism for - quietly performing a key-guessing attack (perhaps using idle CPU - cycles of the infected host) could be at least as effective as Code - Red was. If one assumes that such a worm were engineered to be - maximally stealthy, then steady-state infection could conceivably - reach 1 million hosts or more. That changes our single-CPU - - - -Leech Informational [Page 2] - -RFC 3562 Considerations for the TCP MD5 Signature Option July 2003 - - - performance from 4.1e6 operations per second, to somewhere between - 1.0e11 and 1.0e13 MD5 operations per second. - - In 1997, John Gilmore, and the Electronic Frontier Foundation [EFF98] - developed a special-purpose machine, for an investment of - approximately USD$250,000. This machine was able to mount a - key-guessing attack against DES, and compute a key in under 1 week. - Given Moores Law, the same investment today would yield a machine - that could do the same work approximately 8 times faster. It seems - reasonable to assume that a similar hardware approach could be - brought to bear on key-guessing attacks against MD5, for similar key - lengths to DES, with somewhat-reduced performance (MD5 performance in - hardware may be as much as 2-3 times slower than DES). - -3. Key Lifetimes - - Operational experience with RFC 2385 would suggest that keys used - with this option may have lifetimes on the order of months. It would - seem prudent, then, to choose a minimum key length that guarantees - that key-guessing runtimes are some small multiple of the key-change - interval under best-case (for the attacker) practical attack - performance assumptions. - - The keys used with RFC 2385 are intended only to provide - authentication, and not confidentiality. Consequently, the ability - of an attacker to determine the key used for old traffic (traffic - emitted before a key-change event) is not considered a threat. - -3. Key Entropy - - If we make an assumption that key-change intervals are 90 days, and - that the reasonable upper-bound for software-based attack performance - is 1.0e13 MD5 operations per second, then the minimum required key - entropy is approximately 68 bits. It is reasonable to round this - number up to at least 80 bits, or 10 bytes. If one assumes that - hardware-based attacks are likely, using an EFF-like development - process, but with small-country-sized budgets, then the minimum key - size steps up considerably to around 83 bits, or 11 bytes. Since 11 - is such an ugly number, rounding up to 12 bytes is reasonable. - - In order to achieve this much entropy with an English-language key, - one needs to remember that English has an entropy of approximately - 1.3 bits per character. Other human languages are similar. This - means that a key derived from a human language would need to be - approximately 61 bytes long to produce 80 bits of entropy, and 73 - bytes to produce 96 bits of entropy. - - - - - -Leech Informational [Page 3] - -RFC 3562 Considerations for the TCP MD5 Signature Option July 2003 - - - A more reasonable approach would be to use the techniques described - in [RFC1750] to produce a high quality random key of 96 bits or more. - - It has previously been noted that an attacker will tend to choose - short packets to mount an attack on, since that increases the - key-guessing performance for the attacker. It has also been noted - that MD5 operations are effectively computed in blocks of 64 bytes. - Given that the shortest packet an attacker could reasonably use would - consist of 40 bytes of IP+TCP header data, with no payload, the - remaining 24 bytes of the MD5 block can reasonably be used for keying - material without added CPU cost for routers, but substantially - increase the burden on the attacker. While this practice will tend - to increase the CPU burden for ordinary short BGP packets, since it - will tend to cause the MD5 calculations to overflow into a second MD5 - block, it isn't currently seen to be a significant extra burden to - BGP routing machinery. - - The most reasonable practice, then, would be to choose the largest - possible key length smaller than 25 bytes that is operationally - reasonable, but at least 12 bytes. - - Some implementations restrict the key to a string of ASCII - characters, much like simple passwords, usually of 8 bytes or less. - The very real risk is that such keys are quite vulnerable to - key-guessing attacks, as outlined above. The worst-case scenario - would occur when the ASCII key/password is a human-language word, or - pseudo-word. Such keys/passwords contain, at most, 12 bits of - entropy. In such cases, dictionary driven attacks can yield results - in a fraction of the time that a brute-force approach would take. - Such implementations SHOULD permit users to enter a direct binary key - using the command line interface. One possible implementation would - be to establish a convention that an ASCII key beginning with the - prefix "0x" be interpreted as a string of bytes represented in - hexadecimal. Ideally, such byte strings will have been derived from - a random source, as outlined in [RFC1750]. Implementations SHOULD - NOT limit the length of the key unnecessarily, and SHOULD allow keys - of at least 16 bytes, to allow for the inevitable threat from Moores - Law. - -4. Key management practices - - In current operational use, TCP MD5 Signature keys [RFC2385] may be - shared among significant numbers of systems. Conventional wisdom in - cryptography and security is that such sharing increases the - probability of accidental or deliberate exposure of keys. The more - frequently such keying material is handled, the more likely it is to - be accidentally exposed to unauthorized parties. - - - - -Leech Informational [Page 4] - -RFC 3562 Considerations for the TCP MD5 Signature Option July 2003 - - - Since it is possible for anyone in possession of a key to forge - packets as if they originated with any of the other keyholders, the - most reasonable security practice would be to limit keys to use - between exactly two parties. Current implementations may make this - difficult, but it is the most secure approach when key lifetimes are - long. Reducing key lifetimes can partially mitigate widescale - key-sharing, by limiting the window of opportunity for a "rogue" - keyholder. - - Keying material is extremely sensitive data, and as such, should be - handled with reasonable caution. When keys are transported - electronically, including when configuring network elements like - routers, secure handling techniques MUST be used. Use of protocols - such as S/MIME [RFC2633], TLS [RFC2246], Secure Shell (SSH) SHOULD be - used where appropriate, to protect the transport of the key. - -5. Security Considerations - - This document is entirely about security requirements for keying - material used with RFC 2385. - - No new security exposures are created by this document. - -6. Acknowledgements - - Steve Bellovin, Ran Atkinson, and Randy Bush provided valuable - commentary in the development of this document. - -7. References - - [RFC1771] Rekhter, Y. and T. Li, "A Border Gateway Protocol 4 - (BGP-4)", RFC 1771, March 1995. - - [RFC1810] Touch, J., "Report on MD5 Performance", RFC 1810, June - 1995. - - [RFC2385] Heffernan, A., "Protection of BGP Sessions via the TCP - MD5 Signature Option", RFC 2385, August 1998. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [MDXMAC] Van Oorschot, P. and B. Preneel, "MDx-MAC and Building - Fast MACs from Hash Functions". Proceedings Crypto '95, - Springer-Verlag LNCS, August 1995. - - [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness - Recommendations for Security", RFC 1750, December 1994. - - - -Leech Informational [Page 5] - -RFC 3562 Considerations for the TCP MD5 Signature Option July 2003 - - - [EFF98] "Cracking DES: Secrets of Encryption Research, Wiretap - Politics, and Chip Design". Electronic Frontier - Foundation, 1998. - - [RFC2633] Ramsdell, B., "S/MIME Version 3 Message Specification", - RFC 2633, June 1999. - - [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", - RFC 2246, January 1999. - - [CAIDA2001] "CAIDA Analysis of Code Red" - http://www.caida.org/analysis/security/code-red/ - -8. Author's Address - - Marcus D. Leech - Nortel Networks - P.O. Box 3511, Station C - Ottawa, ON - Canada, K1Y 4H7 - - Phone: +1 613-763-9145 - EMail: mleech@nortelnetworks.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Leech Informational [Page 6] - -RFC 3562 Considerations for the TCP MD5 Signature Option July 2003 - - -9. Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assignees. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Leech Informational [Page 7] - diff --git a/ext/picotcp/RFC/rfc3708.txt b/ext/picotcp/RFC/rfc3708.txt deleted file mode 100644 index 6bd7489..0000000 --- a/ext/picotcp/RFC/rfc3708.txt +++ /dev/null @@ -1,507 +0,0 @@ - - - - - - -Network Working Group E. Blanton -Request for Comments: 3708 Purdue University -Category: Experimental M. Allman - ICIR - February 2004 - - - Using TCP Duplicate Selective Acknowledgement (DSACKs) and - Stream Control Transmission Protocol (SCTP) Duplicate - Transmission Sequence Numbers (TSNs) to Detect Spurious - Retransmissions - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2004). All Rights Reserved. - -Abstract - - TCP and Stream Control Transmission Protocol (SCTP) provide - notification of duplicate segment receipt through Duplicate Selective - Acknowledgement (DSACKs) and Duplicate Transmission Sequence Number - (TSN) notification, respectively. This document presents - conservative methods of using this information to identify - unnecessary retransmissions for various applications. - -1. Introduction - - TCP [RFC793] and SCTP [RFC2960] provide notification of duplicate - segment receipt through duplicate selective acknowledgment (DSACK) - [RFC2883] and Duplicate TSN notifications, respectively. Using this - information, a TCP or SCTP sender can generally determine when a - retransmission was sent in error. This document presents two methods - for using duplicate notifications. The first method is simple and - can be used for accounting applications. The second method is a - conservative algorithm to disambiguate unnecessary retransmissions - from loss events for the purpose of undoing unnecessary congestion - control changes. - - - - - - - -Blanton & Allman Experimental [Page 1] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - - This document is intended to outline reasonable and safe algorithms - for detecting spurious retransmissions and discuss some of the - considerations involved. It is not intended to describe the only - possible method for achieving the goal, although the guidelines in - this document should be taken into consideration when designing - alternate algorithms. Additionally, this document does not outline - what a TCP or SCTP sender may do after a spurious retransmission is - detected. A number of proposals have been developed (e.g., - [RFC3522], [SK03], [BDA03]), but it is not yet clear which of these - proposals are appropriate. In addition, they all rely on detecting - spurious retransmits and so can share the algorithm specified in this - document. - - Finally, we note that to simplify the text much of the following - discussion is in terms of TCP DSACKs, while applying to both TCP and - SCTP. - - Terminology - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in RFC 2119 [RFC2119]. - -2. Counting Duplicate Notifications - - For certain applications a straight count of duplicate notifications - will suffice. For instance, if a stack simply wants to know (for - some reason) the number of spuriously retransmitted segments, - counting all duplicate notifications for retransmitted segments - should work well. Another application of this strategy is to monitor - and adapt transport algorithms so that the transport is not sending - large amounts of spurious data into the network. For instance, - monitoring duplicate notifications could be used by the Early - Retransmit [AAAB03] algorithm to determine whether fast - retransmitting [RFC2581] segments with a lower than normal duplicate - ACK threshold is working, or if segment reordering is causing - spurious retransmits. - - More speculatively, duplicate notification has been proposed as an - integral part of estimating TCP's total loss rate [AEO03] for the - purposes of mitigating the impact of corruption-based losses on - transport protocol performance. [EOA03] proposes altering the - transport's congestion response to the fraction of losses that are - actually due to congestion by requiring the network to provide the - corruption-based loss rate and making the transport sender estimate - the total loss rate. Duplicate notifications are a key part of - estimating the total loss rate accurately [AEO03]. - - - - -Blanton & Allman Experimental [Page 2] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - -3. Congestion/Duplicate Disambiguation Algorithm - - When the purpose of detecting spurious retransmissions is to "undo" - unnecessary changes made to the congestion control state, as - suggested in [RFC2883], the data sender ideally needs to determine: - - (a) That spurious retransmissions in a particular window of data do - not mask real segment loss (congestion). - - For example, assume segments N and N+1 are retransmitted even - though only segment N was dropped by the network (thus, segment - N+1 was needlessly retransmitted). When the sender receives the - notification that segment N+1 arrived more than once it can - conclude that segment N+1 was needlessly resent. However, it - cannot conclude that it is appropriate to revert the congestion - control state because the window of data contained at least one - valid congestion indication (i.e., segment N was lost). - - (b) That network duplication is not the cause of the duplicate - notification. - - Determining whether a duplicate notification is caused by network - duplication of a packet or a spurious retransmit is a nearly - impossible task in theory. Since [Pax97] shows that packet - duplication by the network is rare, the algorithm in this section - simply ceases to function when network duplication is detected - (by receiving a duplication notification for a segment that was - not retransmitted by the sender). - - The algorithm specified below gives reasonable, but not complete, - protection against both of these cases. - - We assume the TCP sender has a data structure to hold selective - acknowledgment information (e.g., as outlined in [RFC3517]). The - following steps require an extension of such a 'scoreboard' to - incorporate a slightly longer history of retransmissions than called - for in [RFC3517]. The following steps MUST be taken upon the receipt - of each DSACK or duplicate TSN notification: - - (A) Check the corresponding sequence range or TSN to determine - whether the segment has been retransmitted. - - (A.1) If the SACK scoreboard is empty (i.e., the TCP sender has - received no SACK information from the receiver) and the - left edge of the incoming DSACK is equal to SND.UNA, - processing of this DSACK MUST be terminated and the - congestion control state MUST NOT be reverted during the - current window of data. This clause intends to cover the - - - -Blanton & Allman Experimental [Page 3] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - - case when an entire window of acknowledgments have been - dropped by the network. In such a case, the reverse path - seems to be in a congested state and so reducing TCP's - sending rate is the conservative approach. - - (A.2) If the segment was retransmitted exactly one time, mark it - as a duplicate. - - (A.3) If the segment was retransmitted more than once processing - of this DSACK MUST be terminated and the congestion control - state MUST NOT be reverted to its previous state during the - current window of data. - - (A.4) If the segment was not retransmitted the incoming DSACK - indicates that the network duplicated the segment in - question. Processing of this DSACK MUST be terminated. In - addition, the algorithm specified in this document MUST NOT - be used for the remainder of the connection, as future - DSACK reports may be indicating network duplication rather - than unnecessary retransmission. Note that some techniques - to further disambiguate network duplication from - unnecessary retransmission (e.g., the TCP timestamp option - [RFC1323]) may be used to refine the algorithm in this - document further. Using such a technique in conjunction - with an algorithm similar to the one presented herein may - allow for the continued use of the algorithm in the face of - duplicated segments. We do not delve into such an - algorithm in this document due the current rarity of - network duplication. However, future work should include - tackling this problem. - - (B) Assuming processing is allowed to continue (per the (A) rules), - check all retransmitted segments in the previous window of data. - - (B.1) If all segments or chunks marked as retransmitted have also - been marked as acknowledged and duplicated, we conclude - that all retransmissions in the previous window of data - were spurious and no loss occurred. - - (B.2) If any segment or chunk is still marked as retransmitted - but not marked as duplicate, there are outstanding - retransmissions that could indicate loss within this window - of data. We can make no conclusions based on this - particular DSACK/duplicate TSN notification. - - In addition to keeping the state mentioned in [RFC3517] (for TCP) and - [RFC2960] (for SCTP), an implementation of this algorithm must track - - - - -Blanton & Allman Experimental [Page 4] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - - all sequence numbers or TSNs that have been acknowledged as - duplicates. - -4. Related Work - - In addition to the mechanism for detecting spurious retransmits - outlined in this document, several other proposals for finding - needless retransmits have been developed. - - [BA02] uses the algorithm outlined in this document as the basis for - investigating several methods to make TCP more robust to reordered - packets. - - The Eifel detection algorithm [RFC3522] uses the TCP timestamp option - [RFC1323] to determine whether the ACK for a given retransmit is for - the original transmission or a retransmission. More generally, - [LK00] outlines the benefits of detecting spurious retransmits and - reverting from needless congestion control changes using the - timestamp-based scheme or a mechanism that uses a "retransmit bit" to - flag retransmits (and ACKs of retransmits). The Eifel detection - algorithm can detect spurious retransmits more rapidly than a DSACK- - based scheme. However, the tradeoff is that the overhead of the 12- - byte timestamp option must be incurred in every packet transmitted - for Eifel to function. - - The F-RTO scheme [SK03] slightly alters TCP's sending pattern - immediately following a retransmission timeout and then observes the - pattern of the returning ACKs. This pattern can indicate whether the - retransmitted segment was needed. The advantage of F-RTO is that the - algorithm only needs to be implemented on the sender side of the TCP - connection and that nothing extra needs to cross the network (e.g., - DSACKs, timestamps, special flags, etc.). The downside is that the - algorithm is a heuristic that can be confused by network pathologies - (e.g., duplication or reordering of key packets). Finally, note that - F-RTO only works for spurious retransmits triggered by the - transport's retransmission timer. - - Finally, [AP99] briefly investigates using the time between - retransmitting a segment via the retransmission timeout and the - arrival of the next ACK as an indicator of whether the retransmit was - needed. The scheme compares this time delta with a fraction (f) of - the minimum RTT observed thus far on the connection. If the time - delta is less than f*minRTT then the retransmit is labeled spurious. - When f=1/2 the algorithm identifies roughly 59% of the needless - retransmission timeouts and identifies needed retransmits only 2.5% - of the time. As with F-RTO, this scheme only detects spurious - retransmits sent by the transport's retransmission timer. - - - - -Blanton & Allman Experimental [Page 5] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - -5. Security Considerations - - It is possible for the receiver to falsely indicate spurious - retransmissions in the case of actual loss, potentially causing a TCP - or SCTP sender to inaccurately conclude that no loss took place (and - possibly cause inappropriate changes to the senders congestion - control state). - - Consider the following scenario: A receiver watches every segment or - chunk that arrives and acknowledges any segment that arrives out of - order by more than some threshold amount as a duplicate, assuming - that it is a retransmission. A sender using the above algorithm will - assume that the retransmission was spurious. - - The ECN nonce sum proposal [RFC3540] could possibly help mitigate the - ability of the receiver to hide real losses from the sender with - modest extension. In the common case of receiving an original - transmission and a spurious retransmit a receiver will have received - the nonce from the original transmission and therefore can "prove" to - the sender that the duplication notification is valid. In the case - when the receiver did not receive the original and is trying to - improperly induce the sender into transmitting at an inappropriately - high rate, the receiver will not know the ECN nonce from the original - segment and therefore will probabilistically not be able to fool the - sender for long. [RFC3540] calls for disabling nonce sums on - duplicate ACKs, which means that the nonce sum is not directly - suitable for use as a mitigation to the problem of receivers lying - about DSACK information. However, future efforts may be able to use - [RFC3540] as a starting point for building protection should it be - needed. - -6. Acknowledgments - - Sourabh Ladha and Reiner Ludwig made several useful comments on an - earlier version of this document. The second author thanks BBN - Technologies and NASA's Glenn Research Center for supporting this - work. - -7. References - -7.1. Normative References - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - - - -Blanton & Allman Experimental [Page 6] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - - [RFC2883] Floyd, S., Mahdavi, J., Mathis, M. and M. Podolsky, "An - Extension to the Selective Acknowledgement (SACK) Option - for TCP", RFC 2883, July 2000. - - [RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C., - Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., Zhang, - L. and V. Paxson, "Stream Control Transmission Protocol", - RFC 2960, October 2000. - -7.2. Informative References - - [AAAB03] Allman, M., Avrachenkov, K., Ayesta, U. and J. Blanton, - "Early Retransmit for TCP", Work in Progress, June 2003. - - [AEO03] Allman, M., Eddy, E. and S. Ostermann, "Estimating Loss - Rates With TCP", Work in Progress, August 2003. - - [AP99] Allman, M. and V. Paxson, "On Estimating End-to-End Network - Path Properties", SIGCOMM 99. - - [BA02] Blanton, E. and M. Allman. On Making TCP More Robust to - Packet Reordering. ACM Computer Communication Review, - 32(1), January 2002. - - [BDA03] Blanton, E., Dimond, R. and M. Allman, "Practices for TCP - Senders in the Face of Segment Reordering", Work in - Progress, February 2003. - - [EOA03] Eddy, W., Ostermann, S. and M. Allman, "New Techniques for - Making Transport Protocols Robust to Corruption-Based - Loss", Work in Progress, July 2003. - - [LK00] R. Ludwig, R. H. Katz. The Eifel Algorithm: Making TCP - Robust Against Spurious Retransmissions. ACM Computer - Communication Review, 30(1), January 2000. - - [Pax97] V. Paxson. End-to-End Internet Packet Dynamics. In ACM - SIGCOMM, September 1997. - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [RFC3517] Blanton, E., Allman, M., Fall, K. and L. Wang, "A - Conservative Selective Acknowledgment (SACK)-based Loss - Recovery Algorithm for TCP", RFC 3517, April 2003. - - [RFC3522] Ludwig, R. and M. Meyer, "The Eifel Detection Algorithm for - TCP," RFC 3522, April 2003. - - - -Blanton & Allman Experimental [Page 7] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - - [RFC3540] Spring, N., Wetherall, D. and D. Ely, "Robust Explicit - Congestion Notification (ECN) Signaling with Nonces", RFC - 3540, June 2003. - - [SK03] Sarolahti, P. and M. Kojo, "F-RTO: An Algorithm for - Detecting Spurious Retransmission Timeouts with TCP and - SCTP", Work in Progress, June 2003. - -8. Authors' Addresses - - Ethan Blanton - Purdue University Computer Sciences - 1398 Computer Science Building - West Lafayette, IN 47907 - - EMail: eblanton@cs.purdue.edu - - - Mark Allman - ICSI Center for Internet Research - 1947 Center Street, Suite 600 - Berkeley, CA 94704-1198 - Phone: 216-243-7361 - - EMail: mallman@icir.org - http://www.icir.org/mallman/ - - - - - - - - - - - - - - - - - - - - - - - - - -Blanton & Allman Experimental [Page 8] - -RFC 3708 TCP DSACKs and SCTP Duplicate TSNs February 2004 - - -9. Full Copyright Statement - - Copyright (C) The Internet Society (2004). This document is subject - to the rights, licenses and restrictions contained in BCP 78 and - except as set forth therein, the authors retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE - REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE - INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF - THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed - to pertain to the implementation or use of the technology - described in this document or the extent to which any license - under such rights might or might not be available; nor does it - represent that it has made any independent effort to identify any - such rights. Information on the procedures with respect to - rights in RFC documents can be found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use - of such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository - at http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention - any copyrights, patents or patent applications, or other - proprietary rights that may cover technology that may be required - to implement this standard. Please address the information to the - IETF at ietf-ipr@ietf.org. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - -Blanton & Allman Experimental [Page 9] - diff --git a/ext/picotcp/RFC/rfc3742.txt b/ext/picotcp/RFC/rfc3742.txt deleted file mode 100644 index 95018d9..0000000 --- a/ext/picotcp/RFC/rfc3742.txt +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - -Network Working Group S. Floyd -Request for Comments: 3742 ICSI -Category: Experimental March 2004 - - - Limited Slow-Start for TCP with Large Congestion Windows - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2004). All Rights Reserved. - -Abstract - - This document describes an optional modification for TCP's slow-start - for use with TCP connections with large congestion windows. For TCP - connections that are able to use congestion windows of thousands (or - tens of thousands) of MSS-sized segments (for MSS the sender's - MAXIMUM SEGMENT SIZE), the current slow-start procedure can result in - increasing the congestion window by thousands of segments in a single - round-trip time. Such an increase can easily result in thousands of - packets being dropped in one round-trip time. This is often - counter-productive for the TCP flow itself, and is also hard on the - rest of the traffic sharing the congested link. This note describes - Limited Slow-Start as an optional mechanism for limiting the number - of segments by which the congestion window is increased for one - window of data during slow-start, in order to improve performance for - TCP connections with large congestion windows. - -1. Introduction - - This note describes an optional modification for TCP's slow-start for - use with TCP connections with large congestion windows. For TCP - connections that are able to use congestion windows of thousands (or - tens of thousands) of MSS-sized segments (for MSS the sender's - MAXIMUM SEGMENT SIZE), the current slow-start procedure can result in - increasing the congestion window by thousands of segments in a single - round-trip time. Such an increase can easily result in thousands of - packets being dropped in one round-trip time. This is often - counter-productive for the TCP flow itself, and is also hard on the - rest of the traffic sharing the congested link. This note describes - Limited Slow-Start, limiting the number of segments by which the - - - -Floyd Experimental [Page 1] - -RFC 3742 TCP's Slow-Start with Large Congestion Windows March 2004 - - - congestion window is increased for one window of data during slow- - start, in order to improve performance for TCP connections with large - congestion windows. - - When slow-start results in a large increase in the congestion window - in one round-trip time, a large number of packets might be dropped in - the network (even with carefully-tuned active queue management - mechanisms in the routers). This drop of a large number of packets - in the network can result in unnecessary retransmit timeouts for the - TCP connection. The TCP connection could end up in the congestion - avoidance phase with a very small congestion window, and could take a - large number of round-trip times to recover its old congestion - window. This poor performance is illustrated in [F02]. - -2. The Proposal for Limited Slow-Start - - Limited Slow-Start introduces a parameter, "max_ssthresh", and - modifies the slow-start mechanism for values of the congestion window - where "cwnd" is greater than "max_ssthresh". That is, during Slow- - Start, when - - cwnd <= max_ssthresh, - - cwnd is increased by one MSS (MAXIMUM SEGMENT SIZE) for every - arriving ACK (acknowledgement) during slow-start, as is always the - case. During Limited Slow-Start, when - - max_ssthresh < cwnd <= ssthresh, - - the invariant is maintained so that the congestion window is - increased during slow-start by at most max_ssthresh/2 MSS per round- - trip time. This is done as follows: - - For each arriving ACK in slow-start: - If (cwnd <= max_ssthresh) - cwnd += MSS; - else - K = int(cwnd/(0.5 max_ssthresh)); - cwnd += int(MSS/K); - - Thus, during Limited Slow-Start the window is increased by 1/K MSS - for each arriving ACK, for K = int(cwnd/(0.5 max_ssthresh)), instead - of by 1 MSS as in standard slow-start [RFC2581]. - - - - - - - - -Floyd Experimental [Page 2] - -RFC 3742 TCP's Slow-Start with Large Congestion Windows March 2004 - - - When - - ssthresh < cwnd, - - slow-start is exited, and the sender is in the Congestion Avoidance - phase. - - Our recommendation would be for max_ssthresh to be set to 100 MSS. - (This is illustrated in the NS [NS] simulator, for snapshots after - May 1, 2002, in the tests "./test-all-tcpHighspeed tcp1A" and - "./test-all-tcpHighspeed tcpHighspeed1" in the subdirectory - "tcl/lib". Setting max_ssthresh to Infinity causes the TCP - connection in NS not to use Limited Slow-Start.) - - With Limited Slow-Start, when the congestion window is greater than - max_ssthresh, the window is increased by at most 1/2 MSS for each - arriving ACK; when the congestion window is greater than 1.5 - max_ssthresh, the window is increased by at most 1/3 MSS for each - arriving ACK, and so on. - - With Limited Slow-Start it takes: - - log(max_ssthresh) - - round-trip times to reach a congestion window of max_ssthresh, and it - takes: - - log(max_ssthresh) + (cwnd - max_ssthresh)/(max_ssthresh/2) - - round-trip times to reach a congestion window of cwnd, for a - congestion window greater than max_ssthresh. - - Thus, with Limited Slow-Start with max_ssthresh set to 100 MSS, it - would take 836 round-trip times to reach a congestion window of - 83,000 packets, compared to 16 round-trip times without Limited - Slow-Start (assuming no packet drops). With Limited Slow-Start, the - largest transient queue during slow-start would be 100 packets; - without Limited Slow-Start, the transient queue during Slow-Start - would reach more than 32,000 packets. - - By limiting the maximum increase in the congestion window in a - round-trip time, Limited Slow-Start can reduce the number of drops - during slow-start, and improve the performance of TCP connections - with large congestion windows. - - - - - - - -Floyd Experimental [Page 3] - -RFC 3742 TCP's Slow-Start with Large Congestion Windows March 2004 - - -3. Experimental Results - - Tom Dunigan has added Limited Slow-Start to the Linux 2.4.16 Web100 - kernel, and performed experiments comparing TCP with and without - Limited Slow-Start [D02]. Results so far show improved performance - for TCPs using Limited Slow-Start. There are also several - experiments comparing different values for max_ssthresh. - -4. Related Proposals - - There has been considerable research on mechanisms for the TCP sender - to learn about the limitations of the available bandwidth, and to - exit slow-start before receiving a congestion indication from the - network [VEGAS,H96]. Other proposals set TCP's slow-start parameter - ssthresh based on information from previous TCP connections to the - same destination [WS95,G00]. This document proposes a simple - limitation on slow-start that can be effective in some cases even in - the absence of such mechanisms. The max_ssthresh parameter does not - replace ssthresh, but is an additional parameter. Thus, Limited - Slow-Start could be used in addition to mechanisms for setting - ssthresh. - - Rate-based pacing has also been proposed to improve the performance - of TCP during slow-start [VH97,AD98,KCRP99,ASA00]. We believe that - rate-based pacing could be of significant benefit, and could be used - in addition to the Limited Slow-Start in this proposal. - - Appropriate Byte Counting [RFC3465] proposes that TCP increase its - congestion window as a function of the number of bytes acknowledged, - rather than as a function of the number of ACKs received. - Appropriate Byte Counting is largely orthogonal to this proposal for - Limited Slow-Start. - - Limited Slow-Start is also orthogonal to other proposals to change - mechanisms for exiting slow-start. For example, FACK TCP includes an - overdamping mechanism to decrease the congestion window somewhat more - aggressively when a loss occurs during slow-start [MM96]. It is also - true that larger values for the MSS would reduce the size of the - congestion window in units of MSS needed to fill a given pipe, and - therefore would reduce the size of the transient queue in units of - MSS. - -5. Acknowledgements - - This proposal is part of a larger proposal for HighSpeed TCP for TCP - connections with large congestion windows, and resulted from - simulations done by Evandro de Souza, in joint work with Deb Agarwal. - This proposal for Limited Slow-Start draws in part from discussions - - - -Floyd Experimental [Page 4] - -RFC 3742 TCP's Slow-Start with Large Congestion Windows March 2004 - - - with Tom Kelly, who has used a similar modified slow-start in his own - research with congestion control for high-bandwidth connections. We - also thank Tom Dunigan for his experiments with Limited Slow-Start. - - We thank Andrei Gurtov, Reiner Ludwig, members of the End-to-End - Research Group, and members of the Transport Area Working Group, for - feedback on this document. - -6. Security Considerations - - This proposal makes no changes to the underlying security of TCP. - -7. References - -7.1. Normative References - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC3465] Allman, M., "TCP Congestion Control with Appropriate Byte - Counting (ABC)", RFC 3465, February 2003. - -7.2. Informative References - - [AD98] Mohit Aron and Peter Druschel, "TCP: Improving Start-up - Dynamics by Adaptive Timers and Congestion Control"", - TR98-318, Rice University, 1998. URL "http://cs- - tr.cs.rice.edu/Dienst/UI/2.0/Describe/ncstrl.rice_cs/TR98- - 318/". - - [ASA00] A. Aggarwal, S. Savage, and T. Anderson, "Understanding the - Performance of TCP Pacing", Proceedings of the 2000 IEEE - Infocom Conference, Tel-Aviv, Israel, March, 2000. URL - "http://www.cs.ucsd.edu/~savage/". - - [D02] T. Dunigan, "Floyd's TCP slow-start and AIMD mods", 2002. - URL "http://www.csm.ornl.gov/~dunigan/net100/floyd.html". - - [F02] S. Floyd, "Performance Problems with TCP's Slow-Start", - 2002. URL "http://www.icir.org/floyd/hstcp/slowstart/". - - [G00] A. Gurtov, "TCP Performance in the Presence of Congestion - and Corruption Losses", Master's Thesis, University of - Helsinki, Department of Computer Science, Helsinki, - December 2000. URL - "http://www.cs.helsinki.fi/u/gurtov/papers/ms_thesis.html". - - - - - -Floyd Experimental [Page 5] - -RFC 3742 TCP's Slow-Start with Large Congestion Windows March 2004 - - - [H96] J. C. Hoe, "Improving the Start-up Behavior of a Congestion - Control Scheme for TCP", SIGCOMM 96, 1996. URL - "http://www.acm.org/sigcomm/sigcomm96/program.html". - - [KCRP99] J. Kulik, R. Coulter, D. Rockwell, and C. Partridge, "A - Simulation Study of Paced TCP", BBN Technical Memorandum - No. 1218, 1999. URL - "http://www.ir.bbn.com/documents/techmemos/index.html". - - [MM96] M. Mathis and J. Mahdavi, "Forward Acknowledgment: Refining - TCP Congestion Control", SIGCOMM, August 1996. - - [NS] The Network Simulator (NS). URL - "http://www.isi.edu/nsnam/ns/". - - [VEGAS] Vegas Web Page, University of Arizona. URL - "http://www.cs.arizona.edu/protocols/". - - [VH97] Vikram Visweswaraiah and John Heidemann, "Rate Based Pacing - for TCP", 1997. URL - "http://www.isi.edu/lsam/publications/rate_based_pacing/". - - [WS95] G. Wright and W. Stevens, "TCP/IP Illustrated", Volume 2, - Addison-Wesley Publishing Company, 1995. - -Authors' Address - - Sally Floyd - ICIR (ICSI Center for Internet Research) - - Phone: +1 (510) 666-2989 - EMail: floyd@icir.org - URL: http://www.icir.org/floyd/ - - - - - - - - - - - - - - - - - - -Floyd Experimental [Page 6] - -RFC 3742 TCP's Slow-Start with Large Congestion Windows March 2004 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2004). This document is subject - to the rights, licenses and restrictions contained in BCP 78 and - except as set forth therein, the authors retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE - REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE - INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF - THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed - to pertain to the implementation or use of the technology - described in this document or the extent to which any license - under such rights might or might not be available; nor does it - represent that it has made any independent effort to identify any - such rights. Information on the procedures with respect to - rights in RFC documents can be found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use - of such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository - at http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention - any copyrights, patents or patent applications, or other - proprietary rights that may cover technology that may be required - to implement this standard. Please address the information to the - IETF at ietf-ipr@ietf.org. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - -Floyd Experimental [Page 7] - diff --git a/ext/picotcp/RFC/rfc3782.txt b/ext/picotcp/RFC/rfc3782.txt deleted file mode 100644 index 7df0e7f..0000000 --- a/ext/picotcp/RFC/rfc3782.txt +++ /dev/null @@ -1,1067 +0,0 @@ - - - - - - -Network Working Group S. Floyd -Request for Comments: 3782 ICSI -Obsoletes: 2582 T. Henderson -Category: Standards Track Boeing - A. Gurtov - TeliaSonera - April 2004 - - - The NewReno Modification to TCP's Fast Recovery Algorithm - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2004). All Rights Reserved. - -Abstract - - The purpose of this document is to advance NewReno TCP's Fast - Retransmit and Fast Recovery algorithms in RFC 2582 from Experimental - to Standards Track status. - - The main change in this document relative to RFC 2582 is to specify - the Careful variant of NewReno's Fast Retransmit and Fast Recovery - algorithms. The base algorithm described in RFC 2582 did not attempt - to avoid unnecessary multiple Fast Retransmits that can occur after a - timeout. However, RFC 2582 also defined "Careful" and "Less Careful" - variants that avoid these unnecessary Fast Retransmits, and - recommended the Careful variant. This document specifies the - previously-named "Careful" variant as the basic version of NewReno - TCP. - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 1] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - -1. Introduction - - For the typical implementation of the TCP Fast Recovery algorithm - described in [RFC2581] (first implemented in the 1990 BSD Reno - release, and referred to as the Reno algorithm in [FF96]), the TCP - data sender only retransmits a packet after a retransmit timeout has - occurred, or after three duplicate acknowledgements have arrived - triggering the Fast Retransmit algorithm. A single retransmit - timeout might result in the retransmission of several data packets, - but each invocation of the Fast Retransmit algorithm in RFC 2581 - leads to the retransmission of only a single data packet. - - Problems can arise, therefore, when multiple packets are dropped from - a single window of data and the Fast Retransmit and Fast Recovery - algorithms are invoked. In this case, if the SACK option is - available, the TCP sender has the information to make intelligent - decisions about which packets to retransmit and which packets not to - retransmit during Fast Recovery. This document applies only for TCP - connections that are unable to use the TCP Selective Acknowledgement - (SACK) option, either because the option is not locally supported or - because the TCP peer did not indicate a willingness to use SACK. - - In the absence of SACK, there is little information available to the - TCP sender in making retransmission decisions during Fast Recovery. - From the three duplicate acknowledgements, the sender infers a packet - loss, and retransmits the indicated packet. After this, the data - sender could receive additional duplicate acknowledgements, as the - data receiver acknowledges additional data packets that were already - in flight when the sender entered Fast Retransmit. - - In the case of multiple packets dropped from a single window of data, - the first new information available to the sender comes when the - sender receives an acknowledgement for the retransmitted packet (that - is, the packet retransmitted when Fast Retransmit was first entered). - If there is a single packet drop and no reordering, then the - acknowledgement for this packet will acknowledge all of the packets - transmitted before Fast Retransmit was entered. However, if there - are multiple packet drops, then the acknowledgement for the - retransmitted packet will acknowledge some but not all of the packets - transmitted before the Fast Retransmit. We call this acknowledgement - a partial acknowledgment. - - Along with several other suggestions, [Hoe95] suggested that during - Fast Recovery the TCP data sender responds to a partial - acknowledgment by inferring that the next in-sequence packet has been - lost, and retransmitting that packet. This document describes a - modification to the Fast Recovery algorithm in RFC 2581 that - incorporates a response to partial acknowledgements received during - - - -Floyd, et al. Standards Track [Page 2] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - Fast Recovery. We call this modified Fast Recovery algorithm - NewReno, because it is a slight but significant variation of the - basic Reno algorithm in RFC 2581. This document does not discuss the - other suggestions in [Hoe95] and [Hoe96], such as a change to the - ssthresh parameter during Slow-Start, or the proposal to send a new - packet for every two duplicate acknowledgements during Fast Recovery. - The version of NewReno in this document also draws on other - discussions of NewReno in the literature [LM97, Hen98]. - - We do not claim that the NewReno version of Fast Recovery described - here is an optimal modification of Fast Recovery for responding to - partial acknowledgements, for TCP connections that are unable to use - SACK. Based on our experiences with the NewReno modification in the - NS simulator [NS] and with numerous implementations of NewReno, we - believe that this modification improves the performance of the Fast - Retransmit and Fast Recovery algorithms in a wide variety of - scenarios. - -2. Terminology and Definitions - - In this document, the key words "MUST", "MUST NOT", "REQUIRED", - "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", - and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. This RFC indicates requirement levels for compliant TCP - implementations implementing the NewReno Fast Retransmit and Fast - Recovery algorithms described in this document. - - This document assumes that the reader is familiar with the terms - SENDER MAXIMUM SEGMENT SIZE (SMSS), CONGESTION WINDOW (cwnd), and - FLIGHT SIZE (FlightSize) defined in [RFC2581]. FLIGHT SIZE is - defined as in [RFC2581] as follows: - - FLIGHT SIZE: - The amount of data that has been sent but not yet acknowledged. - -3. The Fast Retransmit and Fast Recovery Algorithms in NewReno - - The standard implementation of the Fast Retransmit and Fast Recovery - algorithms is given in [RFC2581]. This section specifies the basic - NewReno algorithm. Sections 4 through 6 describe some optional - variants, and the motivations behind them, that an implementor may - want to consider when tuning performance for certain network - scenarios. Sections 7 and 8 provide some guidance to implementors - based on experience with NewReno implementations. - - The NewReno modification concerns the Fast Recovery procedure that - begins when three duplicate ACKs are received and ends when either a - retransmission timeout occurs or an ACK arrives that acknowledges all - - - -Floyd, et al. Standards Track [Page 3] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - of the data up to and including the data that was outstanding when - the Fast Recovery procedure began. - - The NewReno algorithm specified in this document differs from the - implementation in [RFC2581] in the introduction of the variable - "recover" in step 1, in the response to a partial or new - acknowledgement in step 5, and in modifications to step 1 and the - addition of step 6 for avoiding multiple Fast Retransmits caused by - the retransmission of packets already received by the receiver. - - The algorithm specified in this document uses a variable "recover", - whose initial value is the initial send sequence number. - - 1) Three duplicate ACKs: - When the third duplicate ACK is received and the sender is not - already in the Fast Recovery procedure, check to see if the - Cumulative Acknowledgement field covers more than "recover". If - so, go to Step 1A. Otherwise, go to Step 1B. - - 1A) Invoking Fast Retransmit: - If so, then set ssthresh to no more than the value given in - equation 1 below. (This is equation 3 from [RFC2581]). - - ssthresh = max (FlightSize / 2, 2*SMSS) (1) - - In addition, record the highest sequence number transmitted in - the variable "recover", and go to Step 2. - - 1B) Not invoking Fast Retransmit: - Do not enter the Fast Retransmit and Fast Recovery procedure. In - particular, do not change ssthresh, do not go to Step 2 to - retransmit the "lost" segment, and do not execute Step 3 upon - subsequent duplicate ACKs. - - 2) Entering Fast Retransmit: - Retransmit the lost segment and set cwnd to ssthresh plus 3*SMSS. - This artificially "inflates" the congestion window by the number - of segments (three) that have left the network and the receiver - has buffered. - - 3) Fast Recovery: - For each additional duplicate ACK received while in Fast - Recovery, increment cwnd by SMSS. This artificially inflates the - congestion window in order to reflect the additional segment that - has left the network. - - - - - - -Floyd, et al. Standards Track [Page 4] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - 4) Fast Recovery, continued: - Transmit a segment, if allowed by the new value of cwnd and the - receiver's advertised window. - - 5) When an ACK arrives that acknowledges new data, this ACK could be - the acknowledgment elicited by the retransmission from step 2, or - elicited by a later retransmission. - - Full acknowledgements: - If this ACK acknowledges all of the data up to and including - "recover", then the ACK acknowledges all the intermediate - segments sent between the original transmission of the lost - segment and the receipt of the third duplicate ACK. Set cwnd to - either (1) min (ssthresh, FlightSize + SMSS) or (2) ssthresh, - where ssthresh is the value set in step 1; this is termed - "deflating" the window. (We note that "FlightSize" in step 1 - referred to the amount of data outstanding in step 1, when Fast - Recovery was entered, while "FlightSize" in step 5 refers to the - amount of data outstanding in step 5, when Fast Recovery is - exited.) If the second option is selected, the implementation is - encouraged to take measures to avoid a possible burst of data, in - case the amount of data outstanding in the network is much less - than the new congestion window allows. A simple mechanism is to - limit the number of data packets that can be sent in response to - a single acknowledgement; this is known as "maxburst_" in the NS - simulator. Exit the Fast Recovery procedure. - - Partial acknowledgements: - If this ACK does *not* acknowledge all of the data up to and - including "recover", then this is a partial ACK. In this case, - retransmit the first unacknowledged segment. Deflate the - congestion window by the amount of new data acknowledged by the - cumulative acknowledgement field. If the partial ACK - acknowledges at least one SMSS of new data, then add back SMSS - bytes to the congestion window. As in Step 3, this artificially - inflates the congestion window in order to reflect the additional - segment that has left the network. Send a new segment if - permitted by the new value of cwnd. This "partial window - deflation" attempts to ensure that, when Fast Recovery eventually - ends, approximately ssthresh amount of data will be outstanding - in the network. Do not exit the Fast Recovery procedure (i.e., - if any duplicate ACKs subsequently arrive, execute Steps 3 and 4 - above). - - For the first partial ACK that arrives during Fast Recovery, also - reset the retransmit timer. Timer management is discussed in - more detail in Section 4. - - - - -Floyd, et al. Standards Track [Page 5] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - 6) Retransmit timeouts: - After a retransmit timeout, record the highest sequence number - transmitted in the variable "recover" and exit the Fast Recovery - procedure if applicable. - - Step 1 specifies a check that the Cumulative Acknowledgement field - covers more than "recover". Because the acknowledgement field - contains the sequence number that the sender next expects to receive, - the acknowledgement "ack_number" covers more than "recover" when: - - ack_number - 1 > recover; - - i.e., at least one byte more of data is acknowledged beyond the - highest byte that was outstanding when Fast Retransmit was last - entered. - - Note that in Step 5, the congestion window is deflated after a - partial acknowledgement is received. The congestion window was - likely to have been inflated considerably when the partial - acknowledgement was received. In addition, depending on the original - pattern of packet losses, the partial acknowledgement might - acknowledge nearly a window of data. In this case, if the congestion - window was not deflated, the data sender might be able to send nearly - a window of data back-to-back. - - This document does not specify the sender's response to duplicate - ACKs when the Fast Retransmit/Fast Recovery algorithm is not invoked. - This is addressed in other documents, such as those describing the - Limited Transmit procedure [RFC3042]. This document also does not - address issues of adjusting the duplicate acknowledgement threshold, - but assumes the threshold specified in the IETF standards; the - current standard is RFC 2581, which specifies a threshold of three - duplicate acknowledgements. - - As a final note, we would observe that in the absence of the SACK - option, the data sender is working from limited information. When - the issue of recovery from multiple dropped packets from a single - window of data is of particular importance, the best alternative - would be to use the SACK option. - -4. Resetting the Retransmit Timer in Response to Partial - Acknowledgements - - One possible variant to the response to partial acknowledgements - specified in Section 3 concerns when to reset the retransmit timer - after a partial acknowledgement. The algorithm in Section 3, Step 5, - resets the retransmit timer only after the first partial ACK. In - this case, if a large number of packets were dropped from a window of - - - -Floyd, et al. Standards Track [Page 6] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - data, the TCP data sender's retransmit timer will ultimately expire, - and the TCP data sender will invoke Slow-Start. (This is illustrated - on page 12 of [F98].) We call this the Impatient variant of NewReno. - We note that the Impatient variant in Section 3 doesn't follow the - recommended algorithm in RFC 2988 of restarting the retransmit timer - after every packet transmission or retransmission [RFC2988, Step - 5.1]. - - In contrast, the NewReno simulations in [FF96] illustrate the - algorithm described above with the modification that the retransmit - timer is reset after each partial acknowledgement. We call this the - Slow-but-Steady variant of NewReno. In this case, for a window with - a large number of packet drops, the TCP data sender retransmits at - most one packet per roundtrip time. (This behavior is illustrated in - the New-Reno TCP simulation of Figure 5 in [FF96], and on page 11 of - [F98]). - - When N packets have been dropped from a window of data for a large - value of N, the Slow-but-Steady variant can remain in Fast Recovery - for N round-trip times, retransmitting one more dropped packet each - round-trip time; for these scenarios, the Impatient variant gives a - faster recovery and better performance. The tests "ns test-suite- - newreno.tcl impatient1" and "ns test-suite-newreno.tcl slow1" in the - NS simulator illustrate such a scenario, where the Impatient variant - performs better than the Slow-but-Steady variant. The Impatient - variant can be particularly important for TCP connections with large - congestion windows, as illustrated by the tests "ns test-suite- - newreno.tcl impatient4" and "ns test-suite-newreno.tcl slow4" in the - NS simulator. - - One can also construct scenarios where the Slow-but-Steady variant - gives better performance than the Impatient variant. As an example, - this occurs when only a small number of packets are dropped, the RTO - is sufficiently small that the retransmit timer expires, and - performance would have been better without a retransmit timeout. The - tests "ns test-suite-newreno.tcl impatient2" and "ns test-suite- - newreno.tcl slow2" in the NS simulator illustrate such a scenario. - - The Slow-but-Steady variant can also achieve higher goodput than the - Impatient variant, by avoiding unnecessary retransmissions. This - could be of special interest for cellular links, where every - transmission costs battery power and money. The tests "ns test- - suite-newreno.tcl impatient3" and "ns test-suite-newreno.tcl slow3" - in the NS simulator illustrate such a scenario. The Slow-but-Steady - variant can also be more robust to delay variation in the network, - where a delay spike might force the Impatient variant into a timeout - and go-back-N recovery. - - - - -Floyd, et al. Standards Track [Page 7] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - Neither of the two variants discussed above are optimal. Our - recommendation is for the Impatient variant, as specified in Section - 3 of this document, because of the poor performance of the Slow-but- - Steady variant for TCP connections with large congestion windows. - - One possibility for a more optimal algorithm would be one that - recovered from multiple packet drops as quickly as does slow-start, - while resetting the retransmit timers after each partial - acknowledgement, as described in the section below. We note, - however, that there is a limitation to the potential performance in - this case in the absence of the SACK option. - -5. Retransmissions after a Partial Acknowledgement - - One possible variant to the response to partial acknowledgements - specified in Section 3 would be to retransmit more than one packet - after each partial acknowledgement, and to reset the retransmit timer - after each retransmission. The algorithm specified in Section 3 - retransmits a single packet after each partial acknowledgement. This - is the most conservative alternative, in that it is the least likely - to result in an unnecessarily-retransmitted packet. A variant that - would recover faster from a window with many packet drops would be to - effectively Slow-Start, retransmitting two packets after each partial - acknowledgement. Such an approach would take less than N roundtrip - times to recover from N losses [Hoe96]. However, in the absence of - SACK, recovering as quickly as slow-start introduces the likelihood - of unnecessarily retransmitting packets, and this could significantly - complicate the recovery mechanisms. - - We note that the response to partial acknowledgements specified in - Section 3 of this document and in RFC 2582 differs from the response - in [FF96], even though both approaches only retransmit one packet in - response to a partial acknowledgement. Step 5 of Section 3 specifies - that the TCP sender responds to a partial ACK by deflating the - congestion window by the amount of new data acknowledged, adding back - SMSS bytes if the partial ACK acknowledges at least SMSS bytes of new - data, and sending a new segment if permitted by the new value of - cwnd. Thus, only one previously-sent packet is retransmitted in - response to each partial acknowledgement, but additional new packets - might be transmitted as well, depending on the amount of new data - acknowledged by the partial acknowledgement. In contrast, the - variant of NewReno illustrated in [FF96] simply set the congestion - window to ssthresh when a partial acknowledgement was received. The - approach in [FF96] is more conservative, and does not attempt to - accurately track the actual number of outstanding packets after a - partial acknowledgement is received. While either of these - approaches gives acceptable performance, the variant specified in - Section 3 recovers more smoothly when multiple packets are dropped - - - -Floyd, et al. Standards Track [Page 8] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - from a window of data. (The [FF96] behavior can be seen in the NS - simulator by setting the variable "partial_window_deflation_" for - "Agent/TCP/Newreno" to 0; the behavior specified in Section 3 is - achieved by setting "partial_window_deflation_" to 1.) - -6. Avoiding Multiple Fast Retransmits - - This section describes the motivation for the sender's state variable - "recover", and discusses possible heuristics for distinguishing - between a retransmitted packet that was dropped, and three duplicate - acknowledgements from the unnecessary retransmission of three - packets. - - In the absence of the SACK option or timestamps, a duplicate - acknowledgement carries no information to identify the data packet or - packets at the TCP data receiver that triggered that duplicate - acknowledgement. In this case, the TCP data sender is unable to - distinguish between a duplicate acknowledgement that results from a - lost or delayed data packet, and a duplicate acknowledgement that - results from the sender's unnecessary retransmission of a data packet - that had already been received at the TCP data receiver. Because of - this, with the Retransmit and Fast Recovery algorithms in Reno TCP, - multiple segment losses from a single window of data can sometimes - result in unnecessary multiple Fast Retransmits (and multiple - reductions of the congestion window) [F94]. - - With the Fast Retransmit and Fast Recovery algorithms in Reno TCP, - the performance problems caused by multiple Fast Retransmits are - relatively minor compared to the potential problems with Tahoe TCP, - which does not implement Fast Recovery. Nevertheless, unnecessary - Fast Retransmits can occur with Reno TCP unless some explicit - mechanism is added to avoid this, such as the use of the "recover" - variable. (This modification is called "bugfix" in [F98], and is - illustrated on pages 7 and 9 of that document. Unnecessary Fast - Retransmits for Reno without "bugfix" is illustrated on page 6 of - [F98].) - - Section 3 of [RFC2582] defined a default variant of NewReno TCP that - did not use the variable "recover", and did not check if duplicate - ACKs cover the variable "recover" before invoking Fast Retransmit. - With this default variant from RFC 2582, the problem of multiple Fast - Retransmits from a single window of data can occur after a Retransmit - Timeout (as in page 8 of [F98]) or in scenarios with reordering (as - in the validation test "./test-all-newreno newreno5_noBF" in - directory "tcl/test" of the NS simulator. This gives performance - similar to that on page 8 of [F03].) RFC 2582 also defined Careful - and Less Careful variants of the NewReno algorithm, and recommended - the Careful variant. - - - -Floyd, et al. Standards Track [Page 9] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - The algorithm specified in Section 3 of this document corresponds to - the Careful variant of NewReno TCP from RFC 2582, and eliminates the - problem of multiple Fast Retransmits. This algorithm uses the - variable "recover", whose initial value is the initial send sequence - number. After each retransmit timeout, the highest sequence number - transmitted so far is recorded in the variable "recover". - - If, after a retransmit timeout, the TCP data sender retransmits three - consecutive packets that have already been received by the data - receiver, then the TCP data sender will receive three duplicate - acknowledgements that do not cover more than "recover". In this - case, the duplicate acknowledgements are not an indication of a new - instance of congestion. They are simply an indication that the - sender has unnecessarily retransmitted at least three packets. - - However, when a retransmitted packet is itself dropped, the sender - can also receive three duplicate acknowledgements that do not cover - more than "recover". In this case, the sender would have been better - off if it had initiated Fast Retransmit. For a TCP that implements - the algorithm specified in Section 3 of this document, the sender - does not infer a packet drop from duplicate acknowledgements in this - scenario. As always, the retransmit timer is the backup mechanism - for inferring packet loss in this case. - - There are several heuristics, based on timestamps or on the amount of - advancement of the cumulative acknowledgement field, that allow the - sender to distinguish, in some cases, between three duplicate - acknowledgements following a retransmitted packet that was dropped, - and three duplicate acknowledgements from the unnecessary - retransmission of three packets [Gur03, GF04]. The TCP sender MAY - use such a heuristic to decide to invoke a Fast Retransmit in some - cases, even when the three duplicate acknowledgements do not cover - more than "recover". - - For example, when three duplicate acknowledgements are caused by the - unnecessary retransmission of three packets, this is likely to be - accompanied by the cumulative acknowledgement field advancing by at - least four segments. Similarly, a heuristic based on timestamps uses - the fact that when there is a hole in the sequence space, the - timestamp echoed in the duplicate acknowledgement is the timestamp of - the most recent data packet that advanced the cumulative - acknowledgement field [RFC1323]. If timestamps are used, and the - sender stores the timestamp of the last acknowledged segment, then - the timestamp echoed by duplicate acknowledgements can be used to - distinguish between a retransmitted packet that was dropped and three - duplicate acknowledgements from the unnecessary retransmission of - three packets. The heuristics are illustrated in the NS simulator in - the validation test "./test-all-newreno". - - - -Floyd, et al. Standards Track [Page 10] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - -6.1. ACK Heuristic - - If the ACK-based heuristic is used, then following the advancement of - the cumulative acknowledgement field, the sender stores the value of - the previous cumulative acknowledgement as prev_highest_ack, and - stores the latest cumulative ACK as highest_ack. In addition, the - following step is performed if Step 1 in Section 3 fails, before - proceeding to Step 1B. - - 1*) If the Cumulative Acknowledgement field didn't cover more than - "recover", check to see if the congestion window is greater than - SMSS bytes and the difference between highest_ack and - prev_highest_ack is at most 4*SMSS bytes. If true, duplicate - ACKs indicate a lost segment (proceed to Step 1A in Section 3). - Otherwise, duplicate ACKs likely result from unnecessary - retransmissions (proceed to Step 1B in Section 3). - - The congestion window check serves to protect against fast retransmit - immediately after a retransmit timeout, similar to the - "exitFastRetrans_" variable in NS. Examples of applying the ACK - heuristic are in validation tests "./test-all-newreno - newreno_rto_loss_ack" and "./test-all-newreno newreno_rto_dup_ack" in - directory "tcl/test" of the NS simulator. - - If several ACKs are lost, the sender can see a jump in the cumulative - ACK of more than three segments, and the heuristic can fail. A - validation test for this scenario is "./test-all-newreno - newreno_rto_loss_ackf". RFC 2581 recommends that a receiver should - send duplicate ACKs for every out-of-order data packet, such as a - data packet received during Fast Recovery. The ACK heuristic is more - likely to fail if the receiver does not follow this advice, because - then a smaller number of ACK losses are needed to produce a - sufficient jump in the cumulative ACK. - -6.2. Timestamp Heuristic - - If this heuristic is used, the sender stores the timestamp of the - last acknowledged segment. In addition, the second paragraph of step - 1 in Section 3 is replaced as follows: - - 1**) If the Cumulative Acknowledgement field didn't cover more than - "recover", check to see if the echoed timestamp in the last - non-duplicate acknowledgment equals the stored timestamp. If - true, duplicate ACKs indicate a lost segment (proceed to Step 1A - in Section 3). Otherwise, duplicate ACKs likely result from - unnecessary retransmissions (proceed to Step 1B in Section 3). - - - - - -Floyd, et al. Standards Track [Page 11] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - Examples of applying the timestamp heuristic are in validation tests - "./test-all-newreno newreno_rto_loss_tsh" and "./test-all-newreno - newreno_rto_dup_tsh". The timestamp heuristic works correctly, both - when the receiver echoes timestamps as specified by [RFC1323], and by - its revision attempts. However, if the receiver arbitrarily echoes - timestamps, the heuristic can fail. The heuristic can also fail if a - timeout was spurious and returning ACKs are not from retransmitted - segments. This can be prevented by detection algorithms such as - [RFC3522]. - -7. Implementation Issues for the Data Receiver - - [RFC2581] specifies that "Out-of-order data segments SHOULD be - acknowledged immediately, in order to accelerate loss recovery." - Neal Cardwell has noted that some data receivers do not send an - immediate acknowledgement when they send a partial acknowledgment, - but instead wait first for their delayed acknowledgement timer to - expire [C98]. As [C98] notes, this severely limits the potential - benefit of NewReno by delaying the receipt of the partial - acknowledgement at the data sender. Echoing RFC 2581, our - recommendation is that the data receiver send an immediate - acknowledgement for an out-of-order segment, even when that out-of- - order segment fills a hole in the buffer. - -8. Implementation Issues for the Data Sender - - In Section 3, Step 5 above, it is noted that implementations should - take measures to avoid a possible burst of data when leaving Fast - Recovery, in case the amount of new data that the sender is eligible - to send due to the new value of the congestion window is large. This - can arise during NewReno when ACKs are lost or treated as pure window - updates, thereby causing the sender to underestimate the number of - new segments that can be sent during the recovery procedure. - Specifically, bursts can occur when the FlightSize is much less than - the new congestion window when exiting from Fast Recovery. One - simple mechanism to avoid a burst of data when leaving Fast Recovery - is to limit the number of data packets that can be sent in response - to a single acknowledgment. (This is known as "maxburst_" in the ns - simulator.) Other possible mechanisms for avoiding bursts include - rate-based pacing, or setting the slow-start threshold to the - resultant congestion window and then resetting the congestion window - to FlightSize. A recommendation on the general mechanism to avoid - excessively bursty sending patterns is outside the scope of this - document. - - An implementation may want to use a separate flag to record whether - or not it is presently in the Fast Recovery procedure. The use of - the value of the duplicate acknowledgment counter for this purpose is - - - -Floyd, et al. Standards Track [Page 12] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - not reliable because it can be reset upon window updates and out-of- - order acknowledgments. - - When not in Fast Recovery, the value of the state variable "recover" - should be pulled along with the value of the state variable for - acknowledgments (typically, "snd_una") so that, when large amounts of - data have been sent and acked, the sequence space does not wrap and - falsely indicate that Fast Recovery should not be entered (Section 3, - step 1, last paragraph). - - It is important for the sender to respond correctly to duplicate ACKs - received when the sender is no longer in Fast Recovery (e.g., because - of a Retransmit Timeout). The Limited Transmit procedure [RFC3042] - describes possible responses to the first and second duplicate - acknowledgements. When three or more duplicate acknowledgements are - received, the Cumulative Acknowledgement field doesn't cover more - than "recover", and a new Fast Recovery is not invoked, it is - important that the sender not execute the Fast Recovery steps (3) and - (4) in Section 3. Otherwise, the sender could end up in a chain of - spurious timeouts. We mention this only because several NewReno - implementations had this bug, including the implementation in the NS - simulator. (This bug in the NS simulator was fixed in July 2003, - with the variable "exitFastRetrans_".) - -9. Simulations - - Simulations with NewReno are illustrated with the validation test - "tcl/test/test-all-newreno" in the NS simulator. The command - "../../ns test-suite-newreno.tcl reno" shows a simulation with Reno - TCP, illustrating the data sender's lack of response to a partial - acknowledgement. In contrast, the command "../../ns test-suite- - newreno.tcl newreno_B" shows a simulation with the same scenario - using the NewReno algorithms described in this paper. - -10. Comparisons between Reno and NewReno TCP - - As we stated in the introduction, we believe that the NewReno - modification described in this document improves the performance of - the Fast Retransmit and Fast Recovery algorithms of Reno TCP in a - wide variety of scenarios. This has been discussed in some depth in - [FF96], which illustrates Reno TCP's poor performance when multiple - packets are dropped from a window of data and also illustrates - NewReno TCP's good performance in that scenario. - - We do, however, know of one scenario where Reno TCP gives better - performance than NewReno TCP, that we describe here for the sake of - completeness. Consider a scenario with no packet loss, but with - sufficient reordering so that the TCP sender receives three duplicate - - - -Floyd, et al. Standards Track [Page 13] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - acknowledgements. This will trigger the Fast Retransmit and Fast - Recovery algorithms. With Reno TCP or with Sack TCP, this will - result in the unnecessary retransmission of a single packet, combined - with a halving of the congestion window (shown on pages 4 and 6 of - [F03]). With NewReno TCP, however, this reordering will also result - in the unnecessary retransmission of an entire window of data (shown - on page 5 of [F03]). - - While Reno TCP performs better than NewReno TCP in the presence of - reordering, NewReno's superior performance in the presence of - multiple packet drops generally outweighs its less optimal - performance in the presence of reordering. (Sack TCP is the - preferred solution, with good performance in both scenarios.) This - document recommends the Fast Retransmit and Fast Recovery algorithms - of NewReno TCP instead of those of Reno TCP for those TCP connections - that do not support SACK. We would also note that NewReno's Fast - Retransmit and Fast Recovery mechanisms are widely deployed in TCP - implementations in the Internet today, as documented in [PF01]. For - example, tests of TCP implementations in several thousand web servers - in 2001 showed that for those TCP connections where the web browser - was not SACK-capable, more web servers used the Fast Retransmit and - Fast Recovery algorithms of NewReno than those of Reno or Tahoe TCP - [PF01]. - -11. Changes Relative to RFC 2582 - - The purpose of this document is to advance the NewReno's Fast - Retransmit and Fast Recovery algorithms in RFC 2582 to Standards - Track. - - The main change in this document relative to RFC 2582 is to specify - the Careful variant of NewReno's Fast Retransmit and Fast Recovery - algorithms. The base algorithm described in RFC 2582 did not attempt - to avoid unnecessary multiple Fast Retransmits that can occur after a - timeout (described in more detail in the section above). However, - RFC 2582 also defined "Careful" and "Less Careful" variants that - avoid these unnecessary Fast Retransmits, and recommended the Careful - variant. This document specifies the previously-named "Careful" - variant as the basic version of NewReno. As described below, this - algorithm uses a variable "recover", whose initial value is the send - sequence number. - - The algorithm specified in Section 3 checks whether the - acknowledgement field of a partial acknowledgement covers *more* than - "recover", as defined in Section 3. Another possible variant would - be to simply require that the acknowledgement field covers *more than - or equal to* "recover" before initiating another Fast Retransmit. We - called this the Less Careful variant in RFC 2582. - - - -Floyd, et al. Standards Track [Page 14] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - There are two separate scenarios in which the TCP sender could - receive three duplicate acknowledgements acknowledging "recover" but - no more than "recover". One scenario would be that the data sender - transmitted four packets with sequence numbers higher than "recover", - that the first packet was dropped in the network, and the following - three packets triggered three duplicate acknowledgements - acknowledging "recover". The second scenario would be that the - sender unnecessarily retransmitted three packets below "recover", and - that these three packets triggered three duplicate acknowledgements - acknowledging "recover". In the absence of SACK, the TCP sender is - unable to distinguish between these two scenarios. - - For the Careful variant of Fast Retransmit, the data sender would - have to wait for a retransmit timeout in the first scenario, but - would not have an unnecessary Fast Retransmit in the second scenario. - For the Less Careful variant to Fast Retransmit, the data sender - would Fast Retransmit as desired in the first scenario, and would - unnecessarily Fast Retransmit in the second scenario. This document - only specifies the Careful variant in Section 3. Unnecessary Fast - Retransmits with the Less Careful variant in scenarios with - reordering are illustrated in page 8 of [F03]. - - The document also specifies two heuristics that the TCP sender MAY - use to decide to invoke Fast Retransmit even when the three duplicate - acknowledgements do not cover more than "recover". These heuristics, - an ACK-based heuristic and a timestamp heuristic, are described in - Sections 6.1 and 6.2 respectively. - -12. Conclusions - - This document specifies the NewReno Fast Retransmit and Fast Recovery - algorithms for TCP. This NewReno modification to TCP can even be - important for TCP implementations that support the SACK option, - because the SACK option can only be used for TCP connections when - both TCP end-nodes support the SACK option. NewReno performs better - than Reno (RFC 2581) in a number of scenarios discussed herein. - - A number of options to the basic algorithm presented in Section 3 are - also described. These include the handling of the retransmission - timer (Section 4), the response to partial acknowledgments (Section - 5), and the value of the congestion window when leaving Fast Recovery - (section 3, step 5). Our belief is that the differences between - these variants of NewReno are small compared to the differences - between Reno and NewReno. That is, the important thing is to - implement NewReno instead of Reno, for a TCP connection without SACK; - it is less important exactly which of the variants of NewReno is - implemented. - - - - -Floyd, et al. Standards Track [Page 15] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - -13. Security Considerations - - RFC 2581 discusses general security considerations concerning TCP - congestion control. This document describes a specific algorithm - that conforms with the congestion control requirements of RFC 2581, - and so those considerations apply to this algorithm, too. There are - no known additional security concerns for this specific algorithm. - -14. Acknowledgements - - Many thanks to Anil Agarwal, Mark Allman, Armando Caro, Jeffrey Hsu, - Vern Paxson, Kacheong Poon, Keyur Shah, and Bernie Volz for detailed - feedback on this document or on its precursor, RFC 2582. - -15. References - -15.1. Normative References - - [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, October 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC2582] Floyd, S. and T. Henderson, "The NewReno Modification to - TCP's Fast Recovery Algorithm", RFC 2582, April 1999. - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [RFC3042] Allman, M., Balakrishnan, H. and S. Floyd, "Enhancing TCP's - Loss Recovery Using Limited Transmit", RFC 3042, January - 2001. - -15.2. Informative References - - [C98] Cardwell, N., "delayed ACKs for retransmitted packets: - ouch!". November 1998, Email to the tcpimpl mailing list, - Message-ID "Pine.LNX.4.02A.9811021421340.26785- - 100000@sake.cs.washington.edu", archived at "http://tcp- - impl.lerc.nasa.gov/tcp-impl". - - - - - - - -Floyd, et al. Standards Track [Page 16] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - [F98] Floyd, S., Revisions to RFC 2001, "Presentation to the - TCPIMPL Working Group", August 1998. URLs - "ftp://ftp.ee.lbl.gov/talks/sf-tcpimpl-aug98.ps" and - "ftp://ftp.ee.lbl.gov/talks/sf-tcpimpl-aug98.pdf". - - [F03] Floyd, S., "Moving NewReno from Experimental to Proposed - Standard? Presentation to the TSVWG Working Group", March - 2003. URLs "http://www.icir.org/floyd/talks/newreno- - Mar03.ps" and "http://www.icir.org/floyd/talks/newreno- - Mar03.pdf". - - [FF96] Fall, K. and S. Floyd, "Simulation-based Comparisons of - Tahoe, Reno and SACK TCP", Computer Communication Review, - July 1996. URL "ftp://ftp.ee.lbl.gov/papers/sacks.ps.Z". - - [F94] Floyd, S., "TCP and Successive Fast Retransmits", Technical - report, October 1994. URL - "ftp://ftp.ee.lbl.gov/papers/fastretrans.ps". - - [GF04] Gurtov, A. and S. Floyd, "Resolving Acknowledgment - Ambiguity in non-SACK TCP", Next Generation Teletraffic and - Wired/Wireless Advanced Networking (NEW2AN'04), February - 2004. URL "http://www.cs.helsinki.fi/u/gurtov/papers/ - heuristics.html". - - [Gur03] Gurtov, A., "[Tsvwg] resolving the problem of unnecessary - fast retransmits in go-back-N", email to the tsvwg mailing - list, message ID <3F25B467.9020609@cs.helsinki.fi>, July - 28, 2003. URL "http://www1.ietf.org/mail-archive/working- - groups/tsvwg/current/msg04334.html". - - [Hen98] Henderson, T., Re: NewReno and the 2001 Revision. September - 1998. Email to the tcpimpl mailing list, Message ID - "Pine.BSI.3.95.980923224136.26134A- - 100000@raptor.CS.Berkeley.EDU", archived at "http://tcp- - impl.lerc.nasa.gov/tcp-impl". - - [Hoe95] Hoe, J., "Startup Dynamics of TCP's Congestion Control and - Avoidance Schemes", Master's Thesis, MIT, 1995. - - [Hoe96] Hoe, J., "Improving the Start-up Behavior of a Congestion - Control Scheme for TCP", ACM SIGCOMM, August 1996. URL - "http://www.acm.org/sigcomm/sigcomm96/program.html". - - [LM97] Lin, D. and R. Morris, "Dynamics of Random Early - Detection", SIGCOMM 97, September 1997. URL - "http://www.acm.org/sigcomm/sigcomm97/program.html". - - - - -Floyd, et al. Standards Track [Page 17] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - - [NS] The Network Simulator (NS). URL - "http://www.isi.edu/nsnam/ns/". - - [PF01] Padhye, J. and S. Floyd, "Identifying the TCP Behavior of - Web Servers", June 2001, SIGCOMM 2001. - - [RFC1323] Jacobson, V., Braden, R. and D. Borman, "TCP Extensions for - High Performance", RFC 1323, May 1992. - - [RFC3517] Blanton, E., Allman, M., Fall, K. and L. Wang, "A - Conservative Selective Acknowledgment (SACK)-based Loss - Recovery Algorithm for TCP", RFC 3517, April 2003. - - [RFC3522] Ludwig, R. and M. Meyer, "The Eifel Detection Algorithm for - TCP", RFC 3522, April 2003. - -Authors' Addresses - - Sally Floyd - International Computer Science Institute - - Phone: +1 (510) 666-2989 - EMail: floyd@acm.org - URL: http://www.icir.org/floyd/ - - - Tom Henderson - The Boeing Company - - EMail: thomas.r.henderson@boeing.com - - - Andrei Gurtov - TeliaSonera - - EMail: andrei.gurtov@teliasonera.com - - - - - - - - - - - - - - - -Floyd, et al. Standards Track [Page 18] - -RFC 3782 NewReno Modification to Fast Recovery Algorithm April 2004 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2004). This document is subject - to the rights, licenses and restrictions contained in BCP 78, and - except as set forth therein, the authors retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE - REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE - INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF - THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed - to pertain to the implementation or use of the technology - described in this document or the extent to which any license - under such rights might or might not be available; nor does it - represent that it has made any independent effort to identify any - such rights. Information on the procedures with respect to - rights in RFC documents can be found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use - of such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository - at http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention - any copyrights, patents or patent applications, or other - proprietary rights that may cover technology that may be required - to implement this standard. Please address the information to the - IETF at ietf-ipr@ietf.org. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - -Floyd, et al. Standards Track [Page 19] - diff --git a/ext/picotcp/RFC/rfc4015.txt b/ext/picotcp/RFC/rfc4015.txt deleted file mode 100644 index fd527a2..0000000 --- a/ext/picotcp/RFC/rfc4015.txt +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - -Network Working Group R. Ludwig -Request for Comments: 4015 Ericsson Research -Category: Standards Track A. Gurtov - HIIT - February 2005 - - - The Eifel Response Algorithm for TCP - -Status of This Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2005). - -Abstract - - Based on an appropriate detection algorithm, the Eifel response - algorithm provides a way for a TCP sender to respond to a detected - spurious timeout. It adapts the retransmission timer to avoid - further spurious timeouts and (depending on the detection algorithm) - can avoid the often unnecessary go-back-N retransmits that would - otherwise be sent. In addition, the Eifel response algorithm - restores the congestion control state in such a way that packet - bursts are avoided. - -1. Introduction - - The Eifel response algorithm relies on a detection algorithm such as - the Eifel detection algorithm, defined in [RFC3522]. That document - contains informative background and motivation context that may be - useful for implementers of the Eifel response algorithm, but it is - not necessary to read [RFC3522] in order to implement the Eifel - response algorithm. Note that alternative response algorithms have - been proposed [BA02] that could also rely on the Eifel detection - algorithm, and alternative detection algorithms have been proposed - [RFC3708], [SK04] that could work together with the Eifel response - algorithm. - - Based on an appropriate detection algorithm, the Eifel response - algorithm provides a way for a TCP sender to respond to a detected - spurious timeout. It adapts the retransmission timer to avoid - - - -Ludwig & Gurtov Standards Track [Page 1] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - further spurious timeouts and (depending on the detection algorithm) - can avoid the often unnecessary go-back-N retransmits that would - otherwise be sent. In addition, the Eifel response algorithm - restores the congestion control state in such a way that packet - bursts are avoided. - - Note: A previous version of the Eifel response algorithm also - included a response to a detected spurious fast retransmit. - However, as a consensus was not reached about how to adapt the - duplicate acknowledgement threshold in that case, that part of the - algorithm was removed for the time being. - -1.1. Terminology - - The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, - SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this - document, are to be interpreted as described in [RFC2119]. - - We refer to the first-time transmission of an octet as the 'original - transmit'. A subsequent transmission of the same octet is referred - to as a 'retransmit'. In most cases, this terminology can also be - applied to data segments. However, when repacketization occurs, a - segment can contain both first-time transmissions and retransmissions - of octets. In that case, this terminology is only consistent when - applied to octets. For the Eifel detection and response algorithms, - this makes no difference, as they also operate correctly when - repacketization occurs. - - We use the term 'acceptable ACK' as defined in [RFC793]. That is an - ACK that acknowledges previously unacknowledged data. We use the - term 'bytes_acked' to refer to the amount (in terms of octets) of - previously unacknowledged data that is acknowledged by the most - recently received acceptable ACK. We use the TCP sender state - variables 'SND.UNA' and 'SND.NXT' as defined in [RFC793]. SND.UNA - holds the segment sequence number of the oldest outstanding segment. - SND.NXT holds the segment sequence number of the next segment the TCP - sender will (re-)transmit. In addition, we define as 'SND.MAX' the - segment sequence number of the next original transmit to be sent. - The definition of SND.MAX is equivalent to the definition of - 'snd_max' in [WS95]. - - We use the TCP sender state variables 'cwnd' (congestion window), and - 'ssthresh' (slow-start threshold), and the term 'FlightSize' as - defined in [RFC2581]. FlightSize is the amount (in terms of octets) - of outstanding data at a given point in time. We use the term - 'Initial Window' (IW) as defined in [RFC3390]. The IW is the size of - the sender's congestion window after the three-way handshake is - completed. We use the TCP sender state variables 'SRTT' and - - - -Ludwig & Gurtov Standards Track [Page 2] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - 'RTTVAR', and the terms 'RTO' and 'G' as defined in [RFC2988]. G is - the clock granularity of the retransmission timer. In addition, we - assume that the TCP sender maintains the value of the latest round- - trip time (RTT) measurement in the (local) variable 'RTT-SAMPLE'. - - We use the TCP sender state variable 'T_last', and the term 'tcpnow' - as used in [RFC2861]. T_last holds the system time when the TCP - sender sent the last data segment, whereas tcpnow is the TCP sender's - current system time. - -2. Appropriate Detection Algorithms - - If the Eifel response algorithm is implemented at the TCP sender, it - MUST be implemented together with a detection algorithm that is - specified in a standards track or experimental RFC. - - Designers of detection algorithms who want their algorithms to work - together with the Eifel response algorithm should reuse the variable - "SpuriousRecovery" with the semantics and defined values specified in - [RFC3522]. In addition, we define the constant LATE_SPUR_TO (set - equal to -1) as another possible value of the variable - SpuriousRecovery. Detection algorithms should set the value of - SpuriousRecovery to LATE_SPUR_TO if the detection of a spurious - retransmit is based on the ACK for the retransmit (as opposed to an - ACK for an original transmit). For example, this applies to - detection algorithms that are based on the DSACK option [RFC3708]. - -3. The Eifel Response Algorithm - - The complete algorithm is specified in section 3.1. In sections 3.2 - - 3.6, we discuss the different steps of the algorithm. - -3.1. The Algorithm - - Given that a TCP sender has enabled a detection algorithm that - complies with the requirements set in Section 2, a TCP sender MAY use - the Eifel response algorithm as defined in this subsection. - - If the Eifel response algorithm is used, the following steps MUST be - taken by the TCP sender, but only upon initiation of a timeout-based - loss recovery. That is when the first timeout-based retransmit is - sent. The algorithm MUST NOT be reinitiated after a timeout-based - loss recovery has already been started but not completed. In - particular, it may not be reinitiated upon subsequent timeouts for - the same segment, or upon retransmitting segments other than the - oldest outstanding segment. - - - - - -Ludwig & Gurtov Standards Track [Page 3] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - (0) Before the variables cwnd and ssthresh get updated when - loss recovery is initiated, set a "pipe_prev" variable as - follows: - pipe_prev <- max (FlightSize, ssthresh) - - Set a "SRTT_prev" variable and a "RTTVAR_prev" variable as - follows: - SRTT_prev <- SRTT + (2 * G) - RTTVAR_prev <- RTTVAR - - (DET) This is a placeholder for a detection algorithm that must - be executed at this point, and that sets the variable - SpuriousRecovery as outlined in Section 2. If - [RFC3522] is used as the detection algorithm, steps (1) - - (6) of that algorithm go here. - - (7) If SpuriousRecovery equals SPUR_TO, then - proceed to step (8); - - else if SpuriousRecovery equals LATE_SPUR_TO, then - proceed to step (9); - - else - proceed to step (DONE). - - (8) Resume the transmission with previously unsent data: - - Set - SND.NXT <- SND.MAX - - (9) Reverse the congestion control state: - - If the acceptable ACK has the ECN-Echo flag [RFC3168] set, - then - proceed to step (DONE); - - else set - cwnd <- FlightSize + min (bytes_acked, IW) - ssthresh <- pipe_prev - - Proceed to step (DONE). - - (10) Interworking with Congestion Window Validation: - - If congestion window validation is implemented according - to [RFC2861], then set - T_last <- tcpnow - - - - -Ludwig & Gurtov Standards Track [Page 4] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - (11) Adapt the conservativeness of the retransmission timer: - - Upon the first RTT-SAMPLE taken from new data; i.e., the - first RTT-SAMPLE that can be derived from an acceptable - ACK for data that was previously unsent when the spurious - timeout occurred, - - if the retransmission timer is implemented according - to [RFC2988], then set - SRTT <- max (SRTT_prev, RTT-SAMPLE) - RTTVAR <- max (RTTVAR_prev, RTT-SAMPLE/2) - RTO <- SRTT + max (G, 4*RTTVAR) - - Run the bounds check on the RTO (rules (2.4) and - (2.5) in [RFC2988]), and restart the - retransmission timer; - - else - appropriately adapt the conservativeness of the - retransmission timer that is implemented. - - (DONE) No further processing. - -3.2. Storing the Current Congestion Control State (Step 0) - - The TCP sender stores in pipe_prev what is considered a safe slow- - start threshold (ssthresh) before loss recovery is initiated; i.e., - before the loss indication is taken into account. This is either the - current FlightSize, if the TCP sender is in congestion avoidance, or - the current ssthresh, if the TCP sender is in slow-start. If the TCP - sender later detects that it has entered loss recovery unnecessarily, - then pipe_prev is used in step (9) to reverse the congestion control - state. Thus, until the loss recovery phase is terminated, pipe_prev - maintains a memory of the congestion control state of the time right - before the loss recovery phase was initiated. A similar approach is - proposed in [RFC2861], where this state is stored in ssthresh - directly after a TCP sender has become idle or application limited. - - There had been debates about whether the value of pipe_prev should be - decayed over time; e.g., upon subsequent timeouts for the same - outstanding segment. We do not require decaying pipe_prev for the - Eifel response algorithm and do not believe that such a conservative - approach should be in place. Instead, we follow the idea of - revalidating the congestion window through slow-start, as suggested - in [RFC2861]. That is, in step (9), the cwnd is reset to a value - that avoids large packet bursts, and ssthresh is reset to the value - of pipe_prev. Note that [RFC2581] and [RFC2861] also do not require - - - - -Ludwig & Gurtov Standards Track [Page 5] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - a decaying of ssthresh after it has been reset in response to a loss - indication, or after a TCP sender has become idle or application - limited. - -3.3. Suppressing the Unnecessary go-back-N Retransmits (Step 8) - - Without the use of the TCP timestamps option [RFC1323], the TCP - sender suffers from the retransmission ambiguity problem [Zh86], - [KP87]. Therefore, when the first acceptable ACK arrives after a - spurious timeout, the TCP sender must assume that this ACK was sent - in response to the retransmit when in fact it was sent in response to - an original transmit. Furthermore, the TCP sender must further - assume that all other segments that were outstanding at that point - were lost. - - Note: Except for certain cases where original ACKs were lost, the - first acceptable ACK cannot carry a DSACK option [RFC2883]. - - Consequently, once the TCP sender's state has been updated after the - first acceptable ACK has arrived, SND.NXT equals SND.UNA. This is - what causes the often unnecessary go-back-N retransmits. From that - point on every arriving acceptable ACK that was sent in response to - an original transmit will advance SND.NXT. But as long as SND.NXT is - smaller than the value that SND.MAX had when the timeout occurred, - those ACKs will clock out retransmits, whether or not the - corresponding original transmits were lost. - - In fact, during this phase the TCP sender breaks 'packet - conservation' [Jac88]. This is because the go-back-N retransmits are - sent during slow-start. For each original transmit leaving the - network, two retransmits are sent into the network as long as SND.NXT - does not equal SND.MAX (see [LK00] for more detail). - - Once a spurious timeout has been detected (upon receipt of an ACK for - an original transmit), it is safe to let the TCP sender resume the - transmission with previously unsent data. Thus, the Eifel response - algorithm changes the TCP sender's state by setting SND.NXT to - SND.MAX. Note that this step is only executed if the variable - SpuriousRecovery equals SPUR_TO, which in turn requires a detection - algorithm such as the Eifel detection algorithm [RFC3522] or the F- - RTO algorithm [SK04] that detects a spurious retransmit based upon - receiving an ACK for an original transmit (as opposed to the ACK for - the retransmit [RFC3708]). - - - - - - - - -Ludwig & Gurtov Standards Track [Page 6] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - -3.4. Reversing the Congestion Control State (Step 9) - - When a TCP sender enters loss recovery, it reduces cwnd and ssthresh. - However, once the TCP sender detects that the loss recovery has been - falsely triggered, this reduction proves unnecessary. We therefore - believe that it is safe to revert to the previous congestion control - state, following the approach of revalidating the congestion window - as outlined below. This is unless the acceptable ACK signals - congestion through the ECN-Echo flag [RFC3168]. In that case, the - TCP sender MUST refrain from reversing congestion control state. - - If the ECN-Echo flag is not set, cwnd is reset to the sum of the - current FlightSize and the minimum of bytes_acked and IW. In some - cases, this can mean that the first few acceptable ACKs that arrive - will not clock out any data segments. Recall that bytes_acked is the - number of bytes that have been acknowledged by the acceptable ACK. - Note that the value of cwnd must not be changed any further for that - ACK, and that the value of FlightSize at this point in time may be - different from the value of FlightSize in step (0). The value of IW - puts a limit on the size of the packet burst that the TCP sender may - send into the network after the Eifel response algorithm has - terminated. The value of IW is considered an acceptable burst size. - It is the amount of data that a TCP sender may send into a yet - "unprobed" network at the beginning of a connection. - - Then ssthresh is reset to the value of pipe_prev. As a result, the - TCP sender either immediately resumes probing the network for more - bandwidth in congestion avoidance, or it slow-starts to what is - considered a safe operating point for the congestion window. - -3.5. Interworking with the CWV Algorithm (Step 10) - - An implementation of the Congestion Window Validation (CWV) algorithm - [RFC2861] could potentially misinterpret a delay spike that caused a - spurious timeout as a phase where the TCP sender had been idle. - Therefore, T_last is reset to prevent the triggering of the CWV - algorithm in this case. - - Note: The term 'idle' implies that the TCP sender has no data - outstanding; i.e., all data sent has been acknowledged [Jac88]. - According to this definition, a TCP sender is not idle while it is - waiting for an acceptable ACK after a timeout. Unfortunately, the - pseudo-code in [RFC2861] does not include a check for the - condition "idle" (SND.UNA == SND.MAX). We therefore had to add - step (10) to the Eifel response algorithm. - - - - - - -Ludwig & Gurtov Standards Track [Page 7] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - -3.6. Adapting the Retransmission Timer (Step 11) - - There is currently only one retransmission timer standardized for TCP - [RFC2988]. We therefore only address that timer explicitly. Future - standards that might define alternatives to [RFC2988] should propose - similar measures to adapt the conservativeness of the retransmission - timer. - - A spurious timeout often results from a delay spike, which is a - sudden increase of the RTT that usually cannot be predicted. After a - delay spike, the RTT may have changed permanently; e.g., due to a - path change, or because the available bandwidth on a bandwidth- - dominated path has decreased. This may often occur with wide-area - wireless access links. In this case, the RTT estimators (SRTT and - RTTVAR) should be reinitialized from the first RTT-SAMPLE taken from - new data according to rule (2.2) of [RFC2988]. That is, from the - first RTT-SAMPLE that can be derived from an acceptable ACK for data - that was previously unsent when the spurious timeout occurred. - - However, a delay spike may only indicate a transient phase, after - which the RTT returns to its previous range of values, or even to - smaller values. Also, a spurious timeout may occur because the TCP - sender's RTT estimators were only inaccurate enough that the - retransmission timer expires "a tad too early". We believe that two - times the clock granularity of the retransmission timer (2 * G) is a - reasonable upper bound on "a tad too early". Thus, when the new RTO - is calculated in step (11), we ensure that it is at least (2 * G) - greater (see also step (0)) than the RTO was before the spurious - timeout occurred. - - Note that other TCP sender processing will usually take place between - steps (10) and (11). During this phase (i.e., before step (11) has - been reached), the RTO is managed according to the rules of - [RFC2988]. We believe that this is sufficiently conservative for the - following reasons. First, the retransmission timer is restarted upon - the acceptable ACK that was used to detect the spurious timeout. As - a result, the delay spike is already implicitly factored in for - segments outstanding at that time. This is discussed in more detail - in [EL04], where this effect is called the "RTO offset". - Furthermore, if timestamps are enabled, a new and valid RTT-SAMPLE - can be derived from that acceptable ACK. This RTT-SAMPLE must be - relatively large, as it includes the delay spike that caused the - spurious timeout. Consequently, the RTT estimators will be updated - rather conservatively. Without timestamps the RTO will stay - conservatively backed-off due to Karn's algorithm [RFC2988] until the - first RTT-SAMPLE can be derived from an acceptable ACK for data that - was previously unsent when the spurious timeout occurred. - - - - -Ludwig & Gurtov Standards Track [Page 8] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - For the new RTO to become effective, the retransmission timer has to - be restarted. This is consistent with [RFC2988], which recommends - restarting the retransmission timer with the arrival of an acceptable - ACK. - -4. Advanced Loss Recovery is Crucial for the Eifel Response Algorithm - - We have studied environments where spurious timeouts and multiple - losses from the same flight of packets often coincide [GL02], [GL03]. - In such a case, the oldest outstanding segment arrives at the TCP - receiver, but one or more packets from the remaining outstanding - flight are lost. In those environments, end-to-end performance - suffers if the Eifel response algorithm is operated without an - advanced loss recovery scheme such as a SACK-based scheme [RFC3517] - or NewReno [RFC3782]. The reason is TCP-Reno's aggressiveness after - a spurious timeout. Even though TCP-Reno breaks 'packet - conservation' (see Section 3.3) when blindly retransmitting all - outstanding segments, it usually recovers all packets lost from that - flight within a single round-trip time. On the contrary, the more - conservative TCP-Reno-with-Eifel is often forced into another - timeout. Thus, we recommend that the Eifel response algorithm always - be operated in combination with [RFC3517] or [RFC3782]. Additional - robustness is achieved with the Limited Transmit and Early Retransmit - algorithms [RFC3042], [AAAB04]. - - Note: The SACK-based scheme we used for our simulations in [GL02] - and [GL03] is different from the SACK-based scheme that later got - standardized [RFC3517]. The key difference is that [RFC3517] is - more robust to multiple losses from the same flight. It is less - conservative in declaring that a packet has left the network, and - is therefore less dependent on timeouts to recover genuine packet - losses. - - If the NewReno algorithm [RFC3782] is used in combination with the - Eifel response algorithm, step (1) of the NewReno algorithm SHOULD be - modified as follows, but only if SpuriousRecovery equals SPUR_TO: - - (1) Three duplicate ACKs: - When the third duplicate ACK is received and the sender is - not already in the Fast Recovery procedure, go to step 1A. - - That is, the entire step 1B of the NewReno algorithm is obsolete - because step (8) of the Eifel response algorithm avoids the case - where three duplicate ACKs result from unnecessary go-back-N - retransmits after a timeout. Step (8) of the Eifel response - algorithm avoids such unnecessary go-back-N retransmits in the first - place. However, recall that step (8) is only executed if the - variable SpuriousRecovery equals SPUR_TO, which in turn requires a - - - -Ludwig & Gurtov Standards Track [Page 9] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - detection algorithm, such as the Eifel detection algorithm [RFC3522] - or the F-RTO algorithm [SK04], that detects a spurious retransmit - based upon receiving an ACK for an original transmit (as opposed to - the ACK for the retransmit [RFC3708]). - -5. Security Considerations - - There is a risk that a detection algorithm is fooled by spoofed ACKs - that make genuine retransmits appear to the TCP sender as spurious - retransmits. When such a detection algorithm is run together with - the Eifel response algorithm, this could effectively disable - congestion control at the TCP sender. Should this become a concern, - the Eifel response algorithm SHOULD only be run together with - detection algorithms that are known to be safe against such "ACK - spoofing attacks". - - For example, the safe variant of the Eifel detection algorithm - [RFC3522], is a reliable method to protect against this risk. - -6. Acknowledgements - - Many thanks to Keith Sklower, Randy Katz, Michael Meyer, Stephan - Baucke, Sally Floyd, Vern Paxson, Mark Allman, Ethan Blanton, Pasi - Sarolahti, Alexey Kuznetsov, and Yogesh Swami for many discussions - that contributed to this work. - -7. References - -7.1. Normative References - - [RFC2581] Allman, M., Paxson, V., and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [RFC3390] Allman, M., Floyd, S., and C. Partridge, "Increasing TCP's - Initial Window", RFC 3390, October 2002. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC3782] Floyd, S., Henderson, T., and A. Gurtov, "The NewReno - Modification to TCP's Fast Recovery Algorithm", RFC 3782, - April 2004. - - [RFC2861] Handley, M., Padhye, J., and S. Floyd, "TCP Congestion - Window Validation", RFC 2861, June 2000. - - [RFC3522] Ludwig, R. and M. Meyer, "The Eifel Detection Algorithm for - TCP", RFC 3522, April 2003. - - - -Ludwig & Gurtov Standards Track [Page 10] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, "The Addition of - Explicit Congestion Notification (ECN) to IP", RFC 3168, - September 2001. - -7.2. Informative References - - [RFC3042] Allman, M., Balakrishnan, H., and S. Floyd, "Enhancing - TCP's Loss Recovery Using Limited Transmit", RFC 3042, - January 2001. - - [AAAB04] Allman, M., Avrachenkov, K., Ayesta, U., and J. Blanton, - Early Retransmit for TCP and SCTP, Work in Progress, July - 2004. - - [BA02] Blanton, E. and M. Allman, On Making TCP More Robust to - Packet Reordering, ACM Computer Communication Review, Vol. - 32, No. 1, January 2002. - - [RFC3708] Blanton, E. and M. Allman, "Using TCP Duplicate Selective - Acknowledgement (DSACKs) and Stream Control Transmission - Protocol (SCTP) Duplicate Transmission Sequence Numbers - (TSNs) to Detect Spurious Retransmissions", RFC 3708, - February 2004. - - [RFC3517] Blanton, E., Allman, M., Fall, K., and L. Wang, "A - Conservative Selective Acknowledgment (SACK)-based Loss - Recovery Algorithm for TCP", RFC 3517, April 2003. - - [EL04] Ekstrom, H. and R. Ludwig, The Peak-Hopper: A New End-to- - End Retransmission Timer for Reliable Unicast Transport, In - Proceedings of IEEE INFOCOM 04, March 2004. - - [RFC2883] Floyd, S., Mahdavi, J., Mathis, M., and M. Podolsky, "An - Extension to the Selective Acknowledgement (SACK) Option - for TCP", RFC 2883, July 2000. - - [GL02] Gurtov, A. and R. Ludwig, Evaluating the Eifel Algorithm - for TCP in a GPRS Network, In Proceedings of the European - Wireless Conference, February 2002. - - [GL03] Gurtov, A. and R. Ludwig, Responding to Spurious Timeouts - in TCP, In Proceedings of IEEE INFOCOM 03, April 2003. - - - -Ludwig & Gurtov Standards Track [Page 11] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - - [Jac88] Jacobson, V., Congestion Avoidance and Control, In - Proceedings of ACM SIGCOMM 88. - - [RFC1323] Jacobson, V., Braden, R., and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [KP87] Karn, P. and C. Partridge, Improving Round-Trip Time - Estimates in Reliable Transport Protocols, In Proceedings - of ACM SIGCOMM 87. - - [LK00] Ludwig, R. and R. H. Katz, The Eifel Algorithm: Making TCP - Robust Against Spurious Retransmissions, ACM Computer - Communication Review, Vol. 30, No. 1, January 2000. - - [SK04] Sarolahti, P. and M. Kojo, F-RTO: An Algorithm for - Detecting Spurious Retransmission Timeouts with TCP and - SCTP, Work in Progress, November 2004. - - [WS95] Wright, G. R. and W. R. Stevens, TCP/IP Illustrated, Volume - 2 (The Implementation), Addison Wesley, January 1995. - - [Zh86] Zhang, L., Why TCP Timers Don't Work Well, In Proceedings - of ACM SIGCOMM 88. - -Authors' Addresses - - Reiner Ludwig - Ericsson Research (EDD) - Ericsson Allee 1 - 52134 Herzogenrath, Germany - - EMail: Reiner.Ludwig@ericsson.com - - - Andrei Gurtov - Helsinki Institute for Information Technology (HIIT) - P.O. Box 9800, FIN-02015 - HUT, Finland - - EMail: andrei.gurtov@cs.helsinki.fi - Homepage: http://www.cs.helsinki.fi/u/gurtov - - - - - - - - - - -Ludwig & Gurtov Standards Track [Page 12] - -RFC 4015 The Eifel Response Algorithm for TCP February 2005 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2005). - - This document is subject to the rights, licenses and restrictions - contained in BCP 78, and except as set forth therein, the authors - retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; nor does it represent that it has - made any independent effort to identify any such rights. Information - on the IETF's procedures with respect to rights in IETF Documents can - be found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use of - such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository at - http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights that may cover technology that may be required to implement - this standard. Please address the information to the IETF at ietf- - ipr@ietf.org. - - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - -Ludwig & Gurtov Standards Track [Page 13] - diff --git a/ext/picotcp/RFC/rfc4022.txt b/ext/picotcp/RFC/rfc4022.txt deleted file mode 100644 index a908dc7..0000000 --- a/ext/picotcp/RFC/rfc4022.txt +++ /dev/null @@ -1,1347 +0,0 @@ - - - - - - -Network Working Group R. Raghunarayan, Ed. -Request for Comments: 4022 Cisco Systems -Obsoletes: 2452, 2012 March 2005 -Category: Standards Track - - - Management Information Base - for the Transmission Control Protocol (TCP) - -Status of This Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2005). - -Abstract - - This memo defines a portion of the Management Information Base (MIB) - for use with network management protocols in the Internet community. - In particular, it describes managed objects used for implementations - of the Transmission Control Protocol (TCP) in an IP version - independent manner. This memo obsoletes RFCs 2452 and 2012. - -Table of Contents - - 1. The Internet-Standard Management Framework . . . . . . . . . 2 - 2. Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 2.1. Relationship to Other MIBs. . . . . . . . . . . . . . . 2 - 3. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 4 - 4. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . 20 - 5. References. . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 5.1. Normative References. . . . . . . . . . . . . . . . . . 20 - 5.2. Informative References. . . . . . . . . . . . . . . . . 21 - 6. Security Considerations . . . . . . . . . . . . . . . . . . . 21 - 7. Contributors. . . . . . . . . . . . . . . . . . . . . . . . . 23 - Editor's Address. . . . . . . . . . . . . . . . . . . . . . . . . 23 - Full Copyright Statement. . . . . . . . . . . . . . . . . . . . . 24 - - - - - - - - -Raghunarayan Standards Track [Page 1] - -RFC 4022 MIB for TCP March 2005 - - -1. The Internet-Standard Management Framework - - For a detailed overview of the documents that describe the current - Internet-Standard Management Framework, please refer to section 7 of - RFC 3410 [RFC3410]. - - Managed objects are accessed via a virtual information store, termed - the Management Information Base or MIB. MIB objects are generally - accessed through the Simple Network Management Protocol (SNMP). - Objects in the MIB are defined using the mechanisms defined in the - Structure of Management Information (SMI). This memo specifies a MIB - module that is compliant to the SMIv2, which is described in STD 58, - RFC 2578 [RFC2578], STD 58, RFC 2579 [RFC2579] and STD 58, RFC 2580 - [RFC2580]. - -2. Overview - - The current TCP-MIB defined in this memo consists of two tables and a - group of scalars: - - - The tcp group of scalars includes two sets of objects: - - o Parameters of a TCP protocol engine. These include - parameters such as the retransmission algorithm in use - (e.g., vanj [VANJ]) and the retransmission timeout values. - - o Statistics of a TCP protocol engine. These include counters - for the number of active/passive opens, input/output - segments, and errors. Discontinuities in the stats are - identified identified via the sysUpTime object, defined in - [RFC3418]. - - - The tcpConnectionTable provides access to status information - for all TCP connections handled by a TCP protocol engine. In - addition, the table reports identification of the operating - system level processes that handle the TCP connections. - - - The tcpListenerTable provides access to information about all - TCP listening endpoints known by a TCP protocol engine. And as - with the connection table, the tcpListenerTable also reports - the identification of the operating system level processes that - handle this listening TCP endpoint. - -2.1. Relationship to Other MIBs - - This section discusses the relationship of this TCP-MIB module to - other MIB modules. - - - - -Raghunarayan Standards Track [Page 2] - -RFC 4022 MIB for TCP March 2005 - - -2.1.1. Relationship to RFC1213-MIB - - TCP related MIB objects were originally defined as part of the - RFC1213-MIB defined in RFC 1213 [RFC1213]. The TCP related objects - of the RFC1213-MIB were later copied into a separate MIB module and - published in RFC 2012 [RFC2012] in SMIv2 format. - - The previous versions of the TCP-MIB both defined the tcpConnTable, - which has been deprecated basically for two reasons: - - (1) The tcpConnTable only supports IPv4. - - The current approach in the IETF is to write IP version neutral - MIBs, based on the InetAddressType and InetAddress constructs - defined in [RFC4001], rather than to have different definitions - for various version of IP. This reduces the amount of overhead - when new objects are introduced, as there is only one place to - add them. Hence, the approach taken in [RFC2452], of having - separate tables, is not continued. - - (2) The tcpConnTable mixes listening endpoints with connections. - - It turns out that connections tend to have a different behaviour - and management access pattern than listening endpoints. - Therefore, splitting the original tcpConnTable into two tables - allows for the addition of specific status and statistics objects - for listening endpoints and connections. - -2.1.2. Relationship to IPV6-TCP-MIB - - The IPV6-TCP-MIB defined in RFC 2452 has been moved to Historic - status because the approach of having separate IP version specific - tables is not followed anymore. Implementation of RFC 2452 is no - longer suggested. - -2.1.3. Relationship to HOST-RESOURCES-MIB and SYSAPPL-MIB - - The tcpConnectionTable and the tcpListenerTable report the - identification of the operating system level process that handles a - connection or a listening endpoint. The value is reported as an - Unsigned32, which is expected to be the same as the hrSWRunIndex of - the HOST-RESOURCES-MIB [RFC2790] (if the value is smaller than - 2147483647) or the sysApplElmtRunIndex of the SYSAPPL-MIB [RFC2287]. - This allows management applications to identify the TCP connections - that belong to an operating system level process, which has proven to - be valuable in operational environments. - - - - - -Raghunarayan Standards Track [Page 3] - -RFC 4022 MIB for TCP March 2005 - - -3. Definitions - -TCP-MIB DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-IDENTITY, OBJECT-TYPE, Integer32, Unsigned32, - Gauge32, Counter32, Counter64, IpAddress, mib-2 - FROM SNMPv2-SMI - MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF - InetAddress, InetAddressType, - InetPortNumber FROM INET-ADDRESS-MIB; - -tcpMIB MODULE-IDENTITY - LAST-UPDATED "200502180000Z" -- 18 February 2005 - ORGANIZATION - "IETF IPv6 MIB Revision Team - http://www.ietf.org/html.charters/ipv6-charter.html" - CONTACT-INFO - "Rajiv Raghunarayan (editor) - - Cisco Systems Inc. - 170 West Tasman Drive - San Jose, CA 95134 - - Phone: +1 408 853 9612 - Email: - - Send comments to " - DESCRIPTION - "The MIB module for managing TCP implementations. - - Copyright (C) The Internet Society (2005). This version - of this MIB module is a part of RFC 4022; see the RFC - itself for full legal notices." - REVISION "200502180000Z" -- 18 February 2005 - DESCRIPTION - "IP version neutral revision, published as RFC 4022." - REVISION "9411010000Z" - DESCRIPTION - "Initial SMIv2 version, published as RFC 2012." - REVISION "9103310000Z" - DESCRIPTION - "The initial revision of this MIB module was part of - MIB-II." - ::= { mib-2 49 } - --- the TCP base variables group - - - - -Raghunarayan Standards Track [Page 4] - -RFC 4022 MIB for TCP March 2005 - - -tcp OBJECT IDENTIFIER ::= { mib-2 6 } - --- Scalars - -tcpRtoAlgorithm OBJECT-TYPE - SYNTAX INTEGER { - other(1), -- none of the following - constant(2), -- a constant rto - rsre(3), -- MIL-STD-1778, Appendix B - vanj(4), -- Van Jacobson's algorithm - rfc2988(5) -- RFC 2988 - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The algorithm used to determine the timeout value used for - retransmitting unacknowledged octets." - ::= { tcp 1 } - -tcpRtoMin OBJECT-TYPE - SYNTAX Integer32 (0..2147483647) - UNITS "milliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The minimum value permitted by a TCP implementation for - the retransmission timeout, measured in milliseconds. - More refined semantics for objects of this type depend - on the algorithm used to determine the retransmission - timeout; in particular, the IETF standard algorithm - rfc2988(5) provides a minimum value." - ::= { tcp 2 } - -tcpRtoMax OBJECT-TYPE - SYNTAX Integer32 (0..2147483647) - UNITS "milliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The maximum value permitted by a TCP implementation for - the retransmission timeout, measured in milliseconds. - More refined semantics for objects of this type depend - on the algorithm used to determine the retransmission - timeout; in particular, the IETF standard algorithm - rfc2988(5) provides an upper bound (as part of an - adaptive backoff algorithm)." - ::= { tcp 3 } - - - - -Raghunarayan Standards Track [Page 5] - -RFC 4022 MIB for TCP March 2005 - - -tcpMaxConn OBJECT-TYPE - SYNTAX Integer32 (-1 | 0..2147483647) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The limit on the total number of TCP connections the entity - can support. In entities where the maximum number of - connections is dynamic, this object should contain the - value -1." - ::= { tcp 4 } - -tcpActiveOpens OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times that TCP connections have made a direct - transition to the SYN-SENT state from the CLOSED state. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 5 } - -tcpPassiveOpens OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times TCP connections have made a direct - transition to the SYN-RCVD state from the LISTEN state. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 6 } - -tcpAttemptFails OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times that TCP connections have made a direct - transition to the CLOSED state from either the SYN-SENT - state or the SYN-RCVD state, plus the number of times that - TCP connections have made a direct transition to the - LISTEN state from the SYN-RCVD state. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - - - -Raghunarayan Standards Track [Page 6] - -RFC 4022 MIB for TCP March 2005 - - - ::= { tcp 7 } - -tcpEstabResets OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of times that TCP connections have made a direct - transition to the CLOSED state from either the ESTABLISHED - state or the CLOSE-WAIT state. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 8 } - -tcpCurrEstab OBJECT-TYPE - SYNTAX Gauge32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of TCP connections for which the current state - is either ESTABLISHED or CLOSE-WAIT." - ::= { tcp 9 } - -tcpInSegs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments received, including those - received in error. This count includes segments received - on currently established connections. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 10 } - -tcpOutSegs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments sent, including those on - current connections but excluding those containing only - retransmitted octets. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - - - -Raghunarayan Standards Track [Page 7] - -RFC 4022 MIB for TCP March 2005 - - - ::= { tcp 11 } - -tcpRetransSegs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments retransmitted; that is, the - number of TCP segments transmitted containing one or more - previously transmitted octets. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 12 } - -tcpInErrs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments received in error (e.g., bad - TCP checksums). - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 14 } - -tcpOutRsts OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of TCP segments sent containing the RST flag. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 15 } - --- { tcp 16 } was used to represent the ipv6TcpConnTable in RFC 2452, --- which has since been obsoleted. It MUST not be used. - -tcpHCInSegs OBJECT-TYPE - SYNTAX Counter64 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments received, including those - received in error. This count includes segments received - - - -Raghunarayan Standards Track [Page 8] - -RFC 4022 MIB for TCP March 2005 - - - on currently established connections. This object is - the 64-bit equivalent of tcpInSegs. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 17 } - -tcpHCOutSegs OBJECT-TYPE - SYNTAX Counter64 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of segments sent, including those on - current connections but excluding those containing only - retransmitted octets. This object is the 64-bit - equivalent of tcpOutSegs. - - Discontinuities in the value of this counter are - indicated via discontinuities in the value of sysUpTime." - ::= { tcp 18 } - - --- The TCP Connection table - -tcpConnectionTable OBJECT-TYPE - SYNTAX SEQUENCE OF TcpConnectionEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table containing information about existing TCP - connections. Note that unlike earlier TCP MIBs, there - is a separate table for connections in the LISTEN state." - ::= { tcp 19 } - -tcpConnectionEntry OBJECT-TYPE - SYNTAX TcpConnectionEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A conceptual row of the tcpConnectionTable containing - information about a particular current TCP connection. - Each row of this table is transient in that it ceases to - exist when (or soon after) the connection makes the - transition to the CLOSED state." - INDEX { tcpConnectionLocalAddressType, - tcpConnectionLocalAddress, - tcpConnectionLocalPort, - tcpConnectionRemAddressType, - - - -Raghunarayan Standards Track [Page 9] - -RFC 4022 MIB for TCP March 2005 - - - tcpConnectionRemAddress, - tcpConnectionRemPort } - ::= { tcpConnectionTable 1 } - -TcpConnectionEntry ::= SEQUENCE { - tcpConnectionLocalAddressType InetAddressType, - tcpConnectionLocalAddress InetAddress, - tcpConnectionLocalPort InetPortNumber, - tcpConnectionRemAddressType InetAddressType, - tcpConnectionRemAddress InetAddress, - tcpConnectionRemPort InetPortNumber, - tcpConnectionState INTEGER, - tcpConnectionProcess Unsigned32 - } - -tcpConnectionLocalAddressType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The address type of tcpConnectionLocalAddress." - ::= { tcpConnectionEntry 1 } - -tcpConnectionLocalAddress OBJECT-TYPE - SYNTAX InetAddress - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The local IP address for this TCP connection. The type - of this address is determined by the value of - tcpConnectionLocalAddressType. - - As this object is used in the index for the - tcpConnectionTable, implementors should be - careful not to create entries that would result in OIDs - with more than 128 subidentifiers; otherwise the information - cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3." - ::= { tcpConnectionEntry 2 } - -tcpConnectionLocalPort OBJECT-TYPE - SYNTAX InetPortNumber - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The local port number for this TCP connection." - ::= { tcpConnectionEntry 3 } - -tcpConnectionRemAddressType OBJECT-TYPE - - - -Raghunarayan Standards Track [Page 10] - -RFC 4022 MIB for TCP March 2005 - - - SYNTAX InetAddressType - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The address type of tcpConnectionRemAddress." - ::= { tcpConnectionEntry 4 } - -tcpConnectionRemAddress OBJECT-TYPE - SYNTAX InetAddress - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The remote IP address for this TCP connection. The type - of this address is determined by the value of - tcpConnectionRemAddressType. - - As this object is used in the index for the - tcpConnectionTable, implementors should be - careful not to create entries that would result in OIDs - with more than 128 subidentifiers; otherwise the information - cannot be accessed by using SNMPv1, SNMPv2c, or SNMPv3." - ::= { tcpConnectionEntry 5 } - -tcpConnectionRemPort OBJECT-TYPE - SYNTAX InetPortNumber - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The remote port number for this TCP connection." - ::= { tcpConnectionEntry 6 } - -tcpConnectionState OBJECT-TYPE - SYNTAX INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11), - deleteTCB(12) - } - MAX-ACCESS read-write - STATUS current - - - -Raghunarayan Standards Track [Page 11] - -RFC 4022 MIB for TCP March 2005 - - - DESCRIPTION - "The state of this TCP connection. - - The value listen(2) is included only for parallelism to the - old tcpConnTable and should not be used. A connection in - LISTEN state should be present in the tcpListenerTable. - - The only value that may be set by a management station is - deleteTCB(12). Accordingly, it is appropriate for an agent - to return a `badValue' response if a management station - attempts to set this object to any other value. - - If a management station sets this object to the value - deleteTCB(12), then the TCB (as defined in [RFC793]) of - the corresponding connection on the managed node is - deleted, resulting in immediate termination of the - connection. - - As an implementation-specific option, a RST segment may be - sent from the managed node to the other TCP endpoint (note, - however, that RST segments are not sent reliably)." - ::= { tcpConnectionEntry 7 } - -tcpConnectionProcess OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The system's process ID for the process associated with - this connection, or zero if there is no such process. This - value is expected to be the same as HOST-RESOURCES-MIB:: - hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some - row in the appropriate tables." - ::= { tcpConnectionEntry 8 } - --- The TCP Listener table - -tcpListenerTable OBJECT-TYPE - SYNTAX SEQUENCE OF TcpListenerEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A table containing information about TCP listeners. A - listening application can be represented in three - possible ways: - - 1. An application that is willing to accept both IPv4 and - IPv6 datagrams is represented by - - - -Raghunarayan Standards Track [Page 12] - -RFC 4022 MIB for TCP March 2005 - - - a tcpListenerLocalAddressType of unknown (0) and - a tcpListenerLocalAddress of ''h (a zero-length - octet-string). - - 2. An application that is willing to accept only IPv4 or - IPv6 datagrams is represented by a - tcpListenerLocalAddressType of the appropriate address - type and a tcpListenerLocalAddress of '0.0.0.0' or '::' - respectively. - - 3. An application that is listening for data destined - only to a specific IP address, but from any remote - system, is represented by a tcpListenerLocalAddressType - of an appropriate address type, with - tcpListenerLocalAddress as the specific local address. - - NOTE: The address type in this table represents the - address type used for the communication, irrespective - of the higher-layer abstraction. For example, an - application using IPv6 'sockets' to communicate via - IPv4 between ::ffff:10.0.0.1 and ::ffff:10.0.0.2 would - use InetAddressType ipv4(1))." - ::= { tcp 20 } - -tcpListenerEntry OBJECT-TYPE - SYNTAX TcpListenerEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A conceptual row of the tcpListenerTable containing - information about a particular TCP listener." - INDEX { tcpListenerLocalAddressType, - tcpListenerLocalAddress, - tcpListenerLocalPort } - ::= { tcpListenerTable 1 } - -TcpListenerEntry ::= SEQUENCE { - tcpListenerLocalAddressType InetAddressType, - tcpListenerLocalAddress InetAddress, - tcpListenerLocalPort InetPortNumber, - tcpListenerProcess Unsigned32 - } - -tcpListenerLocalAddressType OBJECT-TYPE - SYNTAX InetAddressType - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - - - -Raghunarayan Standards Track [Page 13] - -RFC 4022 MIB for TCP March 2005 - - - "The address type of tcpListenerLocalAddress. The value - should be unknown (0) if connection initiations to all - local IP addresses are accepted." - ::= { tcpListenerEntry 1 } - -tcpListenerLocalAddress OBJECT-TYPE - SYNTAX InetAddress - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The local IP address for this TCP connection. - - The value of this object can be represented in three - possible ways, depending on the characteristics of the - listening application: - - 1. For an application willing to accept both IPv4 and - IPv6 datagrams, the value of this object must be - ''h (a zero-length octet-string), with the value - of the corresponding tcpListenerLocalAddressType - object being unknown (0). - - 2. For an application willing to accept only IPv4 or - IPv6 datagrams, the value of this object must be - '0.0.0.0' or '::' respectively, with - tcpListenerLocalAddressType representing the - appropriate address type. - - 3. For an application which is listening for data - destined only to a specific IP address, the value - of this object is the specific local address, with - tcpListenerLocalAddressType representing the - appropriate address type. - - As this object is used in the index for the - tcpListenerTable, implementors should be - careful not to create entries that would result in OIDs - with more than 128 subidentifiers; otherwise the information - cannot be accessed, using SNMPv1, SNMPv2c, or SNMPv3." - ::= { tcpListenerEntry 2 } - -tcpListenerLocalPort OBJECT-TYPE - SYNTAX InetPortNumber - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The local port number for this TCP connection." - ::= { tcpListenerEntry 3 } - - - -Raghunarayan Standards Track [Page 14] - -RFC 4022 MIB for TCP March 2005 - - -tcpListenerProcess OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The system's process ID for the process associated with - this listener, or zero if there is no such process. This - value is expected to be the same as HOST-RESOURCES-MIB:: - hrSWRunIndex or SYSAPPL-MIB::sysApplElmtRunIndex for some - row in the appropriate tables." - ::= { tcpListenerEntry 4 } - - --- The deprecated TCP Connection table - -tcpConnTable OBJECT-TYPE - SYNTAX SEQUENCE OF TcpConnEntry - MAX-ACCESS not-accessible - STATUS deprecated - DESCRIPTION - "A table containing information about existing IPv4-specific - TCP connections or listeners. This table has been - deprecated in favor of the version neutral - tcpConnectionTable." - ::= { tcp 13 } - -tcpConnEntry OBJECT-TYPE - SYNTAX TcpConnEntry - MAX-ACCESS not-accessible - STATUS deprecated - DESCRIPTION - "A conceptual row of the tcpConnTable containing information - about a particular current IPv4 TCP connection. Each row - of this table is transient in that it ceases to exist when - (or soon after) the connection makes the transition to the - CLOSED state." - INDEX { tcpConnLocalAddress, - tcpConnLocalPort, - tcpConnRemAddress, - tcpConnRemPort } - ::= { tcpConnTable 1 } - -TcpConnEntry ::= SEQUENCE { - tcpConnState INTEGER, - tcpConnLocalAddress IpAddress, - tcpConnLocalPort Integer32, - tcpConnRemAddress IpAddress, - tcpConnRemPort Integer32 - - - -Raghunarayan Standards Track [Page 15] - -RFC 4022 MIB for TCP March 2005 - - - } - -tcpConnState OBJECT-TYPE - SYNTAX INTEGER { - closed(1), - listen(2), - synSent(3), - synReceived(4), - established(5), - finWait1(6), - finWait2(7), - closeWait(8), - lastAck(9), - closing(10), - timeWait(11), - deleteTCB(12) - } - MAX-ACCESS read-write - STATUS deprecated - DESCRIPTION - "The state of this TCP connection. - - The only value that may be set by a management station is - deleteTCB(12). Accordingly, it is appropriate for an agent - to return a `badValue' response if a management station - attempts to set this object to any other value. - - If a management station sets this object to the value - deleteTCB(12), then the TCB (as defined in [RFC793]) of - the corresponding connection on the managed node is - deleted, resulting in immediate termination of the - connection. - - As an implementation-specific option, a RST segment may be - sent from the managed node to the other TCP endpoint (note, - however, that RST segments are not sent reliably)." - ::= { tcpConnEntry 1 } - -tcpConnLocalAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS deprecated - DESCRIPTION - "The local IP address for this TCP connection. In the case - of a connection in the listen state willing to - accept connections for any IP interface associated with the - node, the value 0.0.0.0 is used." - ::= { tcpConnEntry 2 } - - - -Raghunarayan Standards Track [Page 16] - -RFC 4022 MIB for TCP March 2005 - - -tcpConnLocalPort OBJECT-TYPE - SYNTAX Integer32 (0..65535) - MAX-ACCESS read-only - STATUS deprecated - DESCRIPTION - "The local port number for this TCP connection." - ::= { tcpConnEntry 3 } - -tcpConnRemAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS deprecated - DESCRIPTION - "The remote IP address for this TCP connection." - ::= { tcpConnEntry 4 } - -tcpConnRemPort OBJECT-TYPE - SYNTAX Integer32 (0..65535) - MAX-ACCESS read-only - STATUS deprecated - DESCRIPTION - "The remote port number for this TCP connection." - ::= { tcpConnEntry 5 } - --- conformance information - -tcpMIBConformance OBJECT IDENTIFIER ::= { tcpMIB 2 } - -tcpMIBCompliances OBJECT IDENTIFIER ::= { tcpMIBConformance 1 } -tcpMIBGroups OBJECT IDENTIFIER ::= { tcpMIBConformance 2 } - --- compliance statements - -tcpMIBCompliance2 MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for systems that implement TCP. - - A number of INDEX objects cannot be - represented in the form of OBJECT clauses in SMIv2 but - have the following compliance requirements, - expressed in OBJECT clause form in this description - clause: - - -- OBJECT tcpConnectionLocalAddressType - -- SYNTAX InetAddressType { ipv4(1), ipv6(2) } - -- DESCRIPTION - -- This MIB requires support for only global IPv4 - - - -Raghunarayan Standards Track [Page 17] - -RFC 4022 MIB for TCP March 2005 - - - -- and IPv6 address types. - -- - -- OBJECT tcpConnectionRemAddressType - -- SYNTAX InetAddressType { ipv4(1), ipv6(2) } - -- DESCRIPTION - -- This MIB requires support for only global IPv4 - -- and IPv6 address types. - -- - -- OBJECT tcpListenerLocalAddressType - -- SYNTAX InetAddressType { unknown(0), ipv4(1), - -- ipv6(2) } - -- DESCRIPTION - -- This MIB requires support for only global IPv4 - -- and IPv6 address types. The type unknown also - -- needs to be supported to identify a special - -- case in the listener table: a listen using - -- both IPv4 and IPv6 addresses on the device. - -- - " - MODULE -- this module - MANDATORY-GROUPS { tcpBaseGroup, tcpConnectionGroup, - tcpListenerGroup } - GROUP tcpHCGroup - DESCRIPTION - "This group is mandatory for systems that are capable - of receiving or transmitting more than 1 million TCP - segments per second. 1 million segments per second will - cause a Counter32 to wrap in just over an hour." - OBJECT tcpConnectionState - SYNTAX INTEGER { closed(1), listen(2), synSent(3), - synReceived(4), established(5), - finWait1(6), finWait2(7), closeWait(8), - lastAck(9), closing(10), timeWait(11) } - MIN-ACCESS read-only - DESCRIPTION - "Write access is not required, nor is support for the value - deleteTCB (12)." - ::= { tcpMIBCompliances 2 } - -tcpMIBCompliance MODULE-COMPLIANCE - STATUS deprecated - DESCRIPTION - "The compliance statement for IPv4-only systems that - implement TCP. In order to be IP version independent, this - compliance statement is deprecated in favor of - tcpMIBCompliance2. However, agents are still encouraged - to implement these objects in order to interoperate with - the deployed base of managers." - - - -Raghunarayan Standards Track [Page 18] - -RFC 4022 MIB for TCP March 2005 - - - MODULE -- this module - MANDATORY-GROUPS { tcpGroup } - OBJECT tcpConnState - MIN-ACCESS read-only - DESCRIPTION - "Write access is not required." - ::= { tcpMIBCompliances 1 } - - --- units of conformance - -tcpGroup OBJECT-GROUP - OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, - tcpMaxConn, tcpActiveOpens, - tcpPassiveOpens, tcpAttemptFails, - tcpEstabResets, tcpCurrEstab, tcpInSegs, - tcpOutSegs, tcpRetransSegs, tcpConnState, - tcpConnLocalAddress, tcpConnLocalPort, - tcpConnRemAddress, tcpConnRemPort, - tcpInErrs, tcpOutRsts } - STATUS deprecated - DESCRIPTION - "The tcp group of objects providing for management of TCP - entities." - ::= { tcpMIBGroups 1 } - -tcpBaseGroup OBJECT-GROUP - OBJECTS { tcpRtoAlgorithm, tcpRtoMin, tcpRtoMax, - tcpMaxConn, tcpActiveOpens, - tcpPassiveOpens, tcpAttemptFails, - tcpEstabResets, tcpCurrEstab, tcpInSegs, - tcpOutSegs, tcpRetransSegs, - tcpInErrs, tcpOutRsts } - STATUS current - DESCRIPTION - "The group of counters common to TCP entities." - ::= { tcpMIBGroups 2 } - -tcpConnectionGroup OBJECT-GROUP - OBJECTS { tcpConnectionState, tcpConnectionProcess } - STATUS current - DESCRIPTION - "The group provides general information about TCP - connections." - ::= { tcpMIBGroups 3 } - -tcpListenerGroup OBJECT-GROUP - OBJECTS { tcpListenerProcess } - - - -Raghunarayan Standards Track [Page 19] - -RFC 4022 MIB for TCP March 2005 - - - STATUS current - DESCRIPTION - "This group has objects providing general information about - TCP listeners." - ::= { tcpMIBGroups 4 } - -tcpHCGroup OBJECT-GROUP - OBJECTS { tcpHCInSegs, tcpHCOutSegs } - STATUS current - DESCRIPTION - "The group of objects providing for counters of high speed - TCP implementations." - ::= { tcpMIBGroups 5 } - -END - -4. Acknowledgements - - This document contains a modified subset of RFC 1213 and updates RFC - 2012 and RFC 2452. Acknowledgements are therefore due to the authors - and editors of these documents for their excellent work. Several - useful comments regarding usability and design were also received - from Kristine Adamson. The authors would like to thank all these - people for their contribution to this effort. - -5. References - -5.1. Normative References - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, DARPA, September 1981. - - [RFC2287] Krupczak, C. and J. Saperia, "Definitions of System-Level - Managed Objects for Applications", RFC 2287, February 1998. - - [RFC2578] McCloghrie, K., Perkins, D., and J. Schoenwaelder, - "Structure of Management Information Version 2 (SMIv2)", - STD 58, RFC 2578, April 1999. - - [RFC2579] McCloghrie, K., Perkins, D., and J. Schoenwaelder, "Textual - Conventions for SMIv2", STD 58, RFC 2579, April 1999. - - [RFC2580] McCloghrie, K., Perkins, D., and J. Schoenwaelder, - "Conformance Statements for SMIv2", STD 58, RFC 2580, April - 1999. - - [RFC2790] Waldbusser, S. and P. Grillo, "Host Resources MIB", RFC - 2790, March 2000. - - - -Raghunarayan Standards Track [Page 20] - -RFC 4022 MIB for TCP March 2005 - - - [RFC4001] Daniele, M., Haberman, B., Routhier, S., and J. - Schoenwaelder, "Textual Conventions for Internet Network - Addresses", RFC 4001, February 2005. - -5.2. Informative References - - [RFC1213] McCloghrie, K. and M. Rose, "Management Information Base - for Network Management of TCP/IP-based internets", RFC - 1213, March 1991. - - [RFC2012] McCloghrie, K., Ed., "SNMPv2 Management Information Base - for the Transmission Control Protocol using SMIv2", RFC - 2012, November 1996. - - [RFC2452] Daniele, M., "IP Version 6 Management Information Base for - the Transmission Control Protocol", RFC 2452, December - 1998. - - [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [RFC3410] Case, J., Mundy, R., Partain, D., and B. Stewart, - "Introduction and Applicability Statements for Internet- - Standard Management Framework", RFC 3410, December 2002. - - [RFC3418] Presuhn, R., Ed., "Management Information Base (MIB) for - the Simple Network Management Protocol (SNMP)", RFC 3418, - December 2002. - - [VANJ] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM - 1988, Stanford, California. - -6. Security Considerations - - There are a number of management objects defined in this MIB module - with a MAX-ACCESS clause of read-write. Such objects may be - considered sensitive or vulnerable in some network environments. The - support for SET operations in a non-secure environment without proper - protection can have a negative effect on network operations. These - are the tables and objects and their sensitivity/vulnerability: - - o The tcpConnectionState and tcpConnState objects have a MAX-ACCESS - clause of read-write, which allows termination of an arbitrary - connection. Unauthorized access could cause a denial of service. - - Some of the readable objects in this MIB module (i.e., objects with a - MAX-ACCESS other than not-accessible) may be considered sensitive or - vulnerable in some network environments. It is thus important to - - - -Raghunarayan Standards Track [Page 21] - -RFC 4022 MIB for TCP March 2005 - - - control even GET and/or NOTIFY access to these objects and possibly - to even encrypt the values of these objects when sending them over - the network via SNMP. These are the tables and objects and their - sensitivity/vulnerability: - - o The tcpConnectionTable and the tcpConnTable contain objects - providing information about the active connections on the device, - the status of these connections, and the associated processes. - This information may be used by an attacker to launch attacks - against known/unknown weakness in certain protocols/applications. - In addition, access to the connection table could also have - privacy implications, as it provides detailed information on - active connections. - - o The tcpListenerTable and the tcpConnTable contain objects - providing information about listeners on an entity. For example, - the tcpListenerLocalPort and tcpConnLocalPort objects can be used - to identify what ports are open on the machine and what attacks - are likely to succeed, without the attacker having to run a port - scanner. - - SNMP versions prior to SNMPv3 did not include adequate security. - Even if the network itself is secure (for example by using IPSec), - even then, there is no control as to who on the secure network is - allowed to access and GET/SET (read/change/create/delete) the objects - in this MIB module. - - It is RECOMMENDED that implementers consider the security features as - provided by the SNMPv3 framework (see [RFC3410], section 8), - including full support for the SNMPv3 cryptographic mechanisms (for - authentication and privacy). - - Further, deployment of SNMP versions prior to SNMPv3 is NOT - RECOMMENDED. Instead, it is RECOMMENDED to deploy SNMPv3 and to - enable cryptographic security. It is then a customer/operator - responsibility to ensure that the SNMP entity giving access to an - instance of this MIB module is properly configured to give access to - the objects only to those principals (users) that have legitimate - rights to indeed GET or SET (change/create/delete) them. - - - - - - - - - - - - -Raghunarayan Standards Track [Page 22] - -RFC 4022 MIB for TCP March 2005 - - -7. Contributors - - This document is an output of the IPv6 MIB revision team, and - contributors to earlier versions of this document include: - - Bill Fenner, AT&T Labs -- Research - EMail: fenner@research.att.com - - Brian Haberman - EMail: brian@innovationslab.net - - Shawn A. Routhier, Wind River - EMail: shawn.routhier@windriver.com - - Juergen Schoenwalder, TU Braunschweig - EMail: schoenw@ibr.cs.tu-bs.de - - Dave Thaler, Microsoft - EMail: dthaler@windows.microsoft.com - - This document updates parts of the MIBs from several documents. RFC - 2012 has been the base document for these updates, and RFC 2452 was - the first document to define the managed objects for implementations - of TCP over IPv6. - - RFC 2012: - - Keith McCloghrie, Cisco Systems (Editor) - EMail: kzm@cisco.com - - RFC 2452: - - Mike Daniele, Compaq Computer Corporation - EMail: daniele@zk3.dec.com - -Editor's Address - - Rajiv Raghunarayan - Cisco Systems Inc. - 170 West Tasman Drive - San Jose, CA 95134 - USA - - EMail: raraghun@cisco.com - - - - - - - -Raghunarayan Standards Track [Page 23] - -RFC 4022 MIB for TCP March 2005 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2005). - - This document is subject to the rights, licenses and restrictions - contained in BCP 78, and except as set forth therein, the authors - retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; nor does it represent that it has - made any independent effort to identify any such rights. Information - on the procedures with respect to rights in RFC documents can be - found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use of - such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository at - http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights that may cover technology that may be required to implement - this standard. Please address the information to the IETF at ietf- - ipr@ietf.org. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - -Raghunarayan Standards Track [Page 24] - diff --git a/ext/picotcp/RFC/rfc4138.txt b/ext/picotcp/RFC/rfc4138.txt deleted file mode 100644 index 4e18add..0000000 --- a/ext/picotcp/RFC/rfc4138.txt +++ /dev/null @@ -1,1291 +0,0 @@ - - - - - - -Network Working Group P. Sarolahti -Request for Comments: 4138 Nokia Research Center -Category: Experimental M. Kojo - University of Helsinki - August 2005 - - - Forward RTO-Recovery (F-RTO): An Algorithm for Detecting - Spurious Retransmission Timeouts with TCP and the - Stream Control Transmission Protocol (SCTP) - -Status of This Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2005). - -Abstract - - Spurious retransmission timeouts cause suboptimal TCP performance - because they often result in unnecessary retransmission of the last - window of data. This document describes the F-RTO detection - algorithm for detecting spurious TCP retransmission timeouts. F-RTO - is a TCP sender-only algorithm that does not require any TCP options - to operate. After retransmitting the first unacknowledged segment - triggered by a timeout, the F-RTO algorithm of the TCP sender - monitors the incoming acknowledgments to determine whether the - timeout was spurious. It then decides whether to send new segments - or retransmit unacknowledged segments. The algorithm effectively - helps to avoid additional unnecessary retransmissions and thereby - improves TCP performance in the case of a spurious timeout. The - F-RTO algorithm can also be applied to the Stream Control - Transmission Protocol (SCTP). - - - - - - - - - - - - - -Sarolahti & Kojo Experimental [Page 1] - -RFC 4138 Forward RTO-Recovery August 2005 - - -Table of Contents - - 1. Introduction . . . . . . . . . . . . . . . . . . . . . . 2 - 1.1. Terminology . . . . . . . . . . . . . . . . . . . . 4 - 2. F-RTO Algorithm . . . . . . . . . . . . . . . . . . . . . 4 - 2.1. The Algorithm . . . . . . . . . . . . . . . . . . . 5 - 2.2. Discussion . . . . . . . . . . . . . . . . . . . . 6 - 3. SACK-Enhanced Version of the F-RTO Algorithm . . . . . . 8 - 4. Taking Actions after Detecting Spurious RTO . . . . . . . 10 - 5. SCTP Considerations . . . . . . . . . . . . . . . . . . . 10 - 6. Security Considerations . . . . . . . . . . . . . . . . . 11 - 7. Acknowledgements . . . . . . . . . . . . . . . . . . . . 12 - 8. References . . . . . . . . . . . . . . . . . . . . . . . 12 - 8.1. Normative References. . . . . . . . . . . . . . . . 12 - 8.2. Informative References. . . . . . . . . . . . . . . 13 - Appendix A: Scenarios . . . . . . . . . . . . . . . . . . . . 15 - Appendix B: SACK-Enhanced F-RTO and Fast Recovery . . . . . . 20 - Appendix C: Discussion of Window-Limited Cases . . . . . . . 21 - -1. Introduction - - The Transmission Control Protocol (TCP) [Pos81] has two methods for - triggering retransmissions. First, the TCP sender relies on incoming - duplicate ACKs, which indicate that the receiver is missing some of - the data. After a required number of successive duplicate ACKs have - arrived at the sender, it retransmits the first unacknowledged - segment [APS99] and continues with a loss recovery algorithm such as - NewReno [FHG04] or SACK-based loss recovery [BAFW03]. Second, the - TCP sender maintains a retransmission timer which triggers - retransmission of segments, if they have not been acknowledged before - the retransmission timeout (RTO) expires. When the retransmission - timeout occurs, the TCP sender enters the RTO recovery where the - congestion window is initialized to one segment and unacknowledged - segments are retransmitted using the slow-start algorithm. The - retransmission timer is adjusted dynamically, based on the measured - round-trip times [PA00]. - - It has been pointed out that the retransmission timer can expire - spuriously and cause unnecessary retransmissions when no segments - have been lost [LK00, GL02, LM03]. After a spurious retransmission - timeout, the late acknowledgments of the original segments arrive at - the sender, usually triggering unnecessary retransmissions of a whole - window of segments during the RTO recovery. Furthermore, after a - spurious retransmission timeout, a conventional TCP sender increases - the congestion window on each late acknowledgment in slow start. - This injects a large number of data segments into the network within - one round-trip time, thus violating the packet conservation principle - [Jac88]. - - - -Sarolahti & Kojo Experimental [Page 2] - -RFC 4138 Forward RTO-Recovery August 2005 - - - There are a number of potential reasons for spurious retransmission - timeouts. First, some mobile networking technologies involve sudden - delay spikes on transmission because of actions taken during a - hand-off. Second, given a low-bandwidth link or some other change in - available bandwidth, arrival of competing traffic (possibly with - higher priority) can cause a sudden increase of round-trip time. - This may trigger a spurious retransmission timeout. A persistently - reliable link layer can also cause a sudden delay when a data frame - and several retransmissions of it are lost for some reason. This - document does not distinguish between the different causes of such a - delay spike. Rather, it discusses the spurious retransmission - timeouts caused by a delay spike in general. - - This document describes the F-RTO detection algorithm. It is based - on the detection mechanism of the "Forward RTO-Recovery" (F-RTO) - algorithm [SKR03] that is used for detecting spurious retransmission - timeouts and thus avoids unnecessary retransmissions following the - retransmission timeout. When the timeout is not spurious, the F-RTO - algorithm reverts back to the conventional RTO recovery algorithm, - and therefore has similar behavior and performance. In contrast to - alternative algorithms proposed for detecting unnecessary - retransmissions (Eifel [LK00], [LM03] and DSACK-based algorithms - [BA04]), F-RTO does not require any TCP options for its operation, - and it can be implemented by modifying only the TCP sender. The - Eifel algorithm uses TCP timestamps [BBJ92] for detecting a spurious - timeout upon arrival of the first acknowledgment after the - retransmission. The DSACK-based algorithms require that the TCP - Selective Acknowledgment Option [MMFR96], with the DSACK extension - [FMMP00], is in use. With DSACK, the TCP receiver can report if it - has received a duplicate segment, enabling the sender to detect - afterwards whether it has retransmitted segments unnecessarily. The - F-RTO algorithm only attempts to detect and avoid unnecessary - retransmissions after an RTO. Eifel and DSACK can also be used for - detecting unnecessary retransmissions caused by other events, such as - packet reordering. - - When an RTO expires, the F-RTO sender retransmits the first - unacknowledged segment as usual [APS99]. Deviating from the normal - operation after a timeout, it then tries to transmit new, previously - unsent data, for the first acknowledgment that arrives after the - timeout, given that the acknowledgment advances the window. If the - second acknowledgment that arrives after the timeout advances the - window (i.e., acknowledges data that was not retransmitted), the F- - RTO sender declares the timeout spurious and exits the RTO recovery. - However, if either of these two acknowledgments is a duplicate ACK, - there will not be sufficient evidence of a spurious timeout. - Therefore, the F-RTO sender retransmits the unacknowledged segments - in slow start similarly to the traditional algorithm. With a - - - -Sarolahti & Kojo Experimental [Page 3] - -RFC 4138 Forward RTO-Recovery August 2005 - - - SACK-enhanced version of the F-RTO algorithm, spurious timeouts may - be detected even if duplicate ACKs arrive after an RTO - retransmission. - - The F-RTO algorithm can also be applied to the Stream Control - Transmission Protocol (SCTP) [Ste00], because SCTP has acknowledgment - and packet retransmission concepts similar to TCP. For convenience, - this document mostly refers to TCP, but the algorithms and other - discussion are valid for SCTP as well. - - This document is organized as follows. Section 2 describes the basic - F-RTO algorithm. Section 3 outlines an optional enhancement to the - F-RTO algorithm that takes advantage of the TCP SACK option. Section - 4 discusses the possible actions to be taken after detecting a - spurious RTO. Section 5 gives considerations on applying F-RTO with - SCTP, and Section 6 discusses the security considerations. - -1.1. Terminology - - The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, - SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this - document, are to be interpreted as described in [RFC2119]. - -2. F-RTO Algorithm - - A timeout is considered spurious if it would have been avoided had - the sender waited longer for an acknowledgment to arrive [LM03]. - F-RTO affects the TCP sender behavior only after a retransmission - timeout. Otherwise, the TCP behavior remains the same. When the RTO - expires, the F-RTO algorithm monitors incoming acknowledgments and if - the TCP sender gets an acknowledgment for a segment that was not - retransmitted due to timeout, the F-RTO algorithm declares a timeout - spurious. The actions taken in response to a spurious timeout are - not specified in this document, but we discuss some alternatives in - Section 4. This section introduces the algorithm and then discusses - the different steps of the algorithm in more detail. - - Following the practice used with the Eifel Detection algorithm - [LM03], we use the "SpuriousRecovery" variable to indicate whether - the retransmission is declared spurious by the sender. This variable - can be used as an input for a corresponding response algorithm. With - F-RTO, the value of SpuriousRecovery can be either SPUR_TO - (indicating a spurious retransmission timeout) or FALSE (indicating - that the timeout is not declared spurious), and the TCP sender should - follow the conventional RTO recovery algorithm. - - - - - - -Sarolahti & Kojo Experimental [Page 4] - -RFC 4138 Forward RTO-Recovery August 2005 - - -2.1. The Algorithm - - A TCP sender MAY implement the basic F-RTO algorithm. If it chooses - to apply the algorithm, the following steps MUST be taken after the - retransmission timer expires. If the sender implements some loss - recovery algorithm other than Reno or NewReno [FHG04], the F-RTO - algorithm SHOULD NOT be entered when earlier fast recovery is - underway. - - 1) When RTO expires, retransmit the first unacknowledged segment and - set SpuriousRecovery to FALSE. Also, store the highest sequence - number transmitted so far in variable "recover". - - 2) When the first acknowledgment after the RTO retransmission arrives - at the sender, the sender chooses one of the following actions, - depending on whether the ACK advances the window or whether it is - a duplicate ACK. - - a) If the acknowledgment is a duplicate ACK OR it acknowledges a - sequence number equal to the value of "recover" OR it does not - acknowledge all of the data that was retransmitted in step 1, - revert to the conventional RTO recovery and continue by - retransmitting unacknowledged data in slow start. Do not enter - step 3 of this algorithm. The SpuriousRecovery variable - remains as FALSE. - - b) Else, if the acknowledgment advances the window AND it is below - the value of "recover", transmit up to two new (previously - unsent) segments and enter step 3 of this algorithm. If the - TCP sender does not have enough unsent data, it can send only - one segment. In addition, the TCP sender MAY override the - Nagle algorithm [Nag84] and immediately send a segment if - needed. Note that sending two segments in this step is allowed - by TCP congestion control requirements [APS99]: An F-RTO TCP - sender simply chooses different segments to transmit. - - If the TCP sender does not have any new data to send, or the - advertised window prohibits new transmissions, the recommended - action is to skip step 3 of this algorithm and continue with - slow start retransmissions, following the conventional RTO - recovery algorithm. However, alternative ways of handling the - window-limited cases that could result in better performance - are discussed in Appendix C. - - 3) When the second acknowledgment after the RTO retransmission - arrives at the sender, the TCP sender either declares the timeout - spurious, or starts retransmitting the unacknowledged segments. - - - - -Sarolahti & Kojo Experimental [Page 5] - -RFC 4138 Forward RTO-Recovery August 2005 - - - a) If the acknowledgment is a duplicate ACK, set the congestion - window to no more than 3 * MSS, and continue with the slow - start algorithm retransmitting unacknowledged segments. The - congestion window can be set to 3 * MSS, because two round-trip - times have elapsed since the RTO, and a conventional TCP sender - would have increased cwnd to 3 during the same time. Leave - SpuriousRecovery set to FALSE. - - b) If the acknowledgment advances the window (i.e., if it - acknowledges data that was not retransmitted after the - timeout), declare the timeout spurious, set SpuriousRecovery to - SPUR_TO, and set the value of the "recover" variable to SND.UNA - (the oldest unacknowledged sequence number [Pos81]). - -2.2. Discussion - - The F-RTO sender takes cautious actions when it receives duplicate - acknowledgments after a retransmission timeout. Because duplicate - ACKs may indicate that segments have been lost, reliably detecting a - spurious timeout is difficult due to the lack of additional - information. Therefore, it is prudent to follow the conventional TCP - recovery in those cases. - - If the first acknowledgment after the RTO retransmission covers the - "recover" point at algorithm step (2a), there is not enough evidence - that a non-retransmitted segment has arrived at the receiver after - the timeout. This is a common case when a fast retransmission is - lost and has been retransmitted again after an RTO, while the rest of - the unacknowledged segments were successfully delivered to the TCP - receiver before the retransmission timeout. Therefore, the timeout - cannot be declared spurious in this case. - - If the first acknowledgment after the RTO retransmission does not - acknowledge all of the data that was retransmitted in step 1, the TCP - sender reverts to the conventional RTO recovery. Otherwise, a - malicious receiver acknowledging partial segments could cause the - sender to declare the timeout spurious in a case where data was lost. - - The TCP sender is allowed to send two new segments in algorithm - branch (2b) because the conventional TCP sender would transmit two - segments when the first new ACK arrives after the RTO retransmission. - If sending new data is not possible in algorithm branch (2b), or if - the receiver window limits the transmission, the TCP sender has to - send something in order to prevent the TCP transfer from stalling. - If no segments were sent, the pipe between sender and receiver might - run out of segments, and no further acknowledgments would arrive. - Therefore, in the window-limited case, the recommendation is to - - - - -Sarolahti & Kojo Experimental [Page 6] - -RFC 4138 Forward RTO-Recovery August 2005 - - - revert to the conventional RTO recovery with slow start - retransmissions. Appendix C discusses some alternative solutions for - window-limited situations. - - If the retransmission timeout is declared spurious, the TCP sender - sets the value of the "recover" variable to SND.UNA in order to allow - fast retransmit [FHG04]. The "recover" variable was proposed for - avoiding unnecessary, multiple fast retransmits when RTO expires - during fast recovery with NewReno TCP. Because the sender - retransmits only the segment that triggered the timeout, the problem - of unnecessary multiple fast retransmits [FHG04] cannot occur. - Therefore, if three duplicate ACKs arrive at the sender after the - timeout, they probably indicate a packet loss, and thus fast - retransmit should be used to allow efficient recovery. If there are - not enough duplicate ACKs arriving at the sender after a packet loss, - the retransmission timer expires again and the sender enters step 1 - of this algorithm. - - When the timeout is declared spurious, the TCP sender cannot detect - whether the unnecessary RTO retransmission was lost. In principle, - the loss of the RTO retransmission should be taken as a congestion - signal. Thus, there is a small possibility that the F-RTO sender - will violate the congestion control rules, if it chooses to fully - revert congestion control parameters after detecting a spurious - timeout. The Eifel detection algorithm has a similar property, while - the DSACK option can be used to detect whether the retransmitted - segment was successfully delivered to the receiver. - - The F-RTO algorithm has a side-effect on the TCP round-trip time - measurement. Because the TCP sender can avoid most of the - unnecessary retransmissions after detecting a spurious timeout, the - sender is able to take round-trip time samples on the delayed - segments. If the regular RTO recovery was used without TCP - timestamps, this would not be possible due to the retransmission - ambiguity. As a result, the RTO is likely to have more accurate and - larger values with F-RTO than with the regular TCP after a spurious - timeout that was triggered due to delayed segments. We believe this - is an advantage in the networks that are prone to delay spikes. - - There are some situations where the F-RTO algorithm may not avoid - unnecessary retransmissions after a spurious timeout. If packet - reordering or packet duplication occurs on the segment that triggered - the spurious timeout, the F-RTO algorithm may not detect the spurious - timeout due to incoming duplicate ACKs. Additionally, if a spurious - timeout occurs during fast recovery, the F-RTO algorithm often cannot - detect the spurious timeout because the segments that were - transmitted before the fast recovery trigger duplicate ACKs. - However, we consider these cases rare, and note that in cases where - - - -Sarolahti & Kojo Experimental [Page 7] - -RFC 4138 Forward RTO-Recovery August 2005 - - - F-RTO fails to detect the spurious timeout, it retransmits the - unacknowledged segments in slow start, and thus performs similarly to - the regular RTO recovery. - -3. SACK-Enhanced Version of the F-RTO Algorithm - - This section describes an alternative version of the F-RTO algorithm - that uses the TCP Selective Acknowledgment Option [MMFR96]. By using - the SACK option, the TCP sender detects spurious timeouts in most of - the cases when packet reordering or packet duplication is present. - If the SACK blocks acknowledge new data that was not transmitted - after the RTO retransmission, the sender may declare the timeout - spurious, even when duplicate ACKs follow the RTO. - - Given that the TCP Selective Acknowledgment Option [MMFR96] is - enabled for a TCP connection, a TCP sender MAY implement the - SACK-enhanced F-RTO algorithm. If the sender applies the - SACK-enhanced F-RTO algorithm, it MUST follow the steps below. This - algorithm SHOULD NOT be applied if the TCP sender is already in SACK - loss recovery when retransmission timeout occurs. However, when - retransmission timeout occurs during existing loss recovery, it - should be possible to apply the principle of F-RTO within certain - limitations. This is a topic for further research. Appendix B - briefly discusses the related issues. - - The steps of the SACK-enhanced version of the F-RTO algorithm are as - follows. - - 1) When the RTO expires, retransmit the first unacknowledged segment - and set SpuriousRecovery to FALSE. Set variable "recover" to - indicate the highest segment transmitted so far. Following the - recommendation in SACK specification [MMFR96], reset the SACK - scoreboard. - - 2) Wait until the acknowledgment of the data retransmitted due to the - timeout arrives at the sender. If duplicate ACKs arrive before - the cumulative acknowledgment for retransmitted data, adjust the - scoreboard according to the incoming SACK information. Stay in - step 2 and wait for the next new acknowledgment. If RTO expires - again, go to step 1 of the algorithm. - - a) if a cumulative ACK acknowledges a sequence number equal to - "recover", revert to the conventional RTO recovery and set the - congestion window to no more than 2 * MSS, like a regular TCP - would do. Do not enter step 3 of this algorithm. - - - - - - -Sarolahti & Kojo Experimental [Page 8] - -RFC 4138 Forward RTO-Recovery August 2005 - - - b) else, if a cumulative ACK acknowledges a sequence number - (smaller than "recover", but larger than SND.UNA) transmit up - to two new (previously unsent) segments and proceed to step 3. - If the TCP sender is not able to transmit any previously unsent - data -- either due to receiver window limitation, or because it - does not have any new data to send -- the recommended action is - to refrain from entering step 3 of this algorithm. Rather, - continue with slow start retransmissions following the - conventional RTO recovery algorithm. - - It is also possible to apply some of the alternatives for - handling window-limited cases discussed in Appendix C. In this - case, the TCP sender should follow the recommendations - concerning acknowledgments of retransmitted segments given in - Appendix B. - - 3) The next acknowledgment arrives at the sender. Either a duplicate - ACK or a new cumulative ACK (advancing the window) applies in this - step. - - a) if the ACK acknowledges a sequence number above "recover", - either in SACK blocks or as a cumulative ACK, set the - congestion window to no more than 3 * MSS and proceed with the - conventional RTO recovery, retransmitting unacknowledged - segments. Take this branch also when the acknowledgment is a - duplicate ACK and it does not acknowledge any new, previously - unacknowledged data below "recover" in the SACK blocks. Leave - SpuriousRecovery set to FALSE. - - b) if the ACK does not acknowledge sequence numbers above - "recover" AND it acknowledges data that was not acknowledged - earlier (either with cumulative acknowledgment or using SACK - blocks), declare the timeout spurious and set SpuriousRecovery - to SPUR_TO. The retransmission timeout can be declared - spurious, because the segment acknowledged with this ACK was - transmitted before the timeout. - - If there are unacknowledged holes between the received SACK blocks, - those segments are retransmitted similarly to the conventional SACK - recovery algorithm [BAFW03]. If the algorithm exits with - SpuriousRecovery set to SPUR_TO, "recover" is set to SND.UNA, thus - allowing fast recovery on incoming duplicate acknowledgments. - - - - - - - - - -Sarolahti & Kojo Experimental [Page 9] - -RFC 4138 Forward RTO-Recovery August 2005 - - -4. Taking Actions after Detecting Spurious RTO - - Upon retransmission timeout, a conventional TCP sender assumes that - outstanding segments are lost and starts retransmitting the - unacknowledged segments. When the retransmission timeout is detected - to be spurious, the TCP sender should not continue retransmitting - based on the timeout. For example, if the sender was in congestion - avoidance phase transmitting new, previously unsent segments, it - should continue transmitting previously unsent segments after - detecting a spurious RTO. This document does not describe the - response to spurious timeouts, but a response algorithm is described - in RFC 4015 [LG04]. - - Additionally, different response variants to spurious retransmission - timeout have been discussed in various research papers [SKR03, GL03, - Sar03] and IETF documents [SL03]. The different response - alternatives vary in whether the spurious retransmission timeout - should be taken as a congestion signal, thus causing the congestion - window or slow start threshold to be reduced at the sender, or - whether the congestion control state should be fully reverted to the - state valid prior to the retransmission timeout. - -5. SCTP Considerations - - SCTP has similar retransmission algorithms and congestion control to - TCP. The SCTP T3-rtx timer for one destination address is maintained - in the same way as the TCP retransmission timer, and after a T3-rtx - expires, an SCTP sender retransmits unacknowledged data chunks in - slow start like TCP does. Therefore, SCTP is vulnerable to the - negative effects of the spurious retransmission timeouts similarly to - TCP. Due to similar RTO recovery algorithms, F-RTO algorithm logic - can be applied also to SCTP. Since SCTP uses selective - acknowledgments, the SACK-based variant of the algorithm is - recommended, although the basic version can also be applied to SCTP. - However, SCTP contains features that are not present with TCP that - need to be discussed when applying the F-RTO algorithm. - - SCTP associations can be multi-homed. The current retransmission - policy states that retransmissions should go to alternative - addresses. If the retransmission was due to spurious timeout caused - by a delay spike, it is possible that the acknowledgment for the - retransmission arrives back at the sender before the acknowledgments - of the original transmissions arrive. If this happens, a possible - loss of the original transmission of the data chunk that was - retransmitted due to the spurious timeout may remain undetected when - applying the F-RTO algorithm. Because the timeout was caused by a - delay spike, and it was spurious in that respect, a suitable response - is to continue by sending new data. However, if the original - - - -Sarolahti & Kojo Experimental [Page 10] - -RFC 4138 Forward RTO-Recovery August 2005 - - - transmission was lost, fully reverting the congestion control - parameters is too aggressive. Therefore, taking conservative actions - on congestion control is recommended, if the SCTP association is - multi-homed and retransmissions go to alternative addresses. The - information in duplicate TSNs can be then used for reverting - congestion control, if desired [BA04]. - - Note that the forward transmissions made in F-RTO algorithm step (2b) - should be destined to the primary address, since they are not - retransmissions. - - When making a retransmission, an SCTP sender can bundle a number of - unacknowledged data chunks and include them in the same packet. This - needs to be considered when implementing F-RTO for SCTP. The basic - principle of F-RTO still holds: in order to declare the timeout - spurious, the sender must get an acknowledgment for a data chunk that - was not retransmitted after the retransmission timeout. In other - words, acknowledgments of data chunks that were bundled in RTO - retransmission must not be used for declaring the timeout spurious. - -6. Security Considerations - - The main security threat regarding F-RTO is the possibility that a - receiver could mislead the sender into setting too large a congestion - window after an RTO. There are two possible ways a malicious - receiver could trigger a wrong output from the F-RTO algorithm. - First, the receiver can acknowledge data that it has not received. - Second, it can delay acknowledgment of a segment it has received - earlier, and acknowledge the segment after the TCP sender has been - deluded to enter algorithm step 3. - - If the receiver acknowledges a segment it has not really received, - the sender can be led to declare spurious timeout in the F-RTO - algorithm, step 3. However, because the sender will have an - incorrect state, it cannot retransmit the segment that has never - reached the receiver. Therefore, this attack is unlikely to be - useful for the receiver to maliciously gain a larger congestion - window. - - A common case for a retransmission timeout is that a fast - retransmission of a segment is lost. If all other segments have been - received, the RTO retransmission causes the whole window to be - acknowledged at once. This case is recognized in F-RTO algorithm - branch (2a). However, if the receiver only acknowledges one segment - after receiving the RTO retransmission, and then the rest of the - segments, it could cause the timeout to be declared spurious when it - is not. Therefore, it is suggested that, when an RTO expires during - - - - -Sarolahti & Kojo Experimental [Page 11] - -RFC 4138 Forward RTO-Recovery August 2005 - - - fast recovery phase, the sender would not fully revert the congestion - window even if the timeout was declared spurious. Instead, the - sender would reduce the congestion window to 1. - - If there is more than one segment missing at the time of a - retransmission timeout, the receiver does not benefit from misleading - the sender to declare a spurious timeout because the sender would - have to go through another recovery period to retransmit the missing - segments, usually after an RTO has elapsed. - -7. Acknowledgements - - We are grateful to Reiner Ludwig, Andrei Gurtov, Josh Blanton, Mark - Allman, Sally Floyd, Yogesh Swami, Mika Liljeberg, Ivan Arias - Rodriguez, Sourabh Ladha, Martin Duke, Motoharu Miyake, Ted Faber, - Samu Kontinen, and Kostas Pentikousis for the discussion and feedback - contributed to this text. - -8. References - -8.1. Normative References - - [APS99] Allman, M., Paxson, V., and W. Stevens, "TCP Congestion - Control", RFC 2581, April 1999. - - [BAFW03] Blanton, E., Allman, M., Fall, K., and L. Wang, "A - Conservative Selective Acknowledgment (SACK)-based Loss - Recovery Algorithm for TCP", RFC 3517, April 2003. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [FHG04] Floyd, S., Henderson, T., and A. Gurtov, "The NewReno - Modification to TCP's Fast Recovery Algorithm", RFC 3782, - April 2004. - - [MMFR96] Mathis, M., Mahdavi, J., Floyd, S., and A. Romanow, "TCP - Selective Acknowledgement Options", RFC 2018, October 1996. - - [PA00] Paxson, V. and M. Allman, "Computing TCP's Retransmission - Timer", RFC 2988, November 2000. - - [Pos81] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - - - - - - -Sarolahti & Kojo Experimental [Page 12] - -RFC 4138 Forward RTO-Recovery August 2005 - - - [Ste00] Stewart, R., Xie, Q., Morneault, K., Sharp, C., - Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., Zhang, - L., and V. Paxson, "Stream Control Transmission Protocol", - RFC 2960, October 2000. - -8.2. Informative References - - [ABF01] Allman, M., Balakrishnan, H., and S. Floyd, "Enhancing - TCP's Loss Recovery Using Limited Transmit", RFC 3042, - January 2001. - - [BA04] Blanton, E. and M. Allman, "Using TCP Duplicate Selective - Acknowledgement (DSACKs) and Stream Control Transmission - Protocol (SCTP) Duplicate Transmission Sequence Numbers - (TSNs) to Detect Spurious Retransmissions", RFC 3708, - February 2004. - - [BBJ92] Jacobson, V., Braden, R., and D. Borman, "TCP Extensions - for High Performance", RFC 1323, May 1992. - - [FMMP00] Floyd, S., Mahdavi, J., Mathis, M., and M. Podolsky, "An - Extension to the Selective Acknowledgement (SACK) Option - for TCP", RFC 2883, July 2000. - - [GL02] A. Gurtov and R. Ludwig. Evaluating the Eifel Algorithm - for TCP in a GPRS Network. In Proc. of European Wireless, - Florence, Italy, February 2002. - - [GL03] A. Gurtov and R. Ludwig, Responding to Spurious Timeouts in - TCP. In Proceedings of IEEE INFOCOM 03, San Francisco, CA, - USA, March 2003. - - [Jac88] V. Jacobson. Congestion Avoidance and Control. In - Proceedings of ACM SIGCOMM 88. - - [LG04] Ludwig, R. and A. Gurtov, "The Eifel Response Algorithm for - TCP", RFC 4015, February 2005. - - [LK00] R. Ludwig and R.H. Katz. The Eifel Algorithm: Making TCP - Robust Against Spurious Retransmissions. ACM SIGCOMM - Computer Communication Review, 30(1), January 2000. - - [LM03] Ludwig, R. and M. Meyer, "The Eifel Detection Algorithm for - TCP", RFC 3522, April 2003. - - [Nag84] Nagle, J., "Congestion Control in IP/TCP Internetworks", - RFC 896, January 1984. - - - - -Sarolahti & Kojo Experimental [Page 13] - -RFC 4138 Forward RTO-Recovery August 2005 - - - [SKR03] P. Sarolahti, M. Kojo, and K. Raatikainen. F-RTO: An - Enhanced Recovery Algorithm for TCP Retransmission - Timeouts. ACM SIGCOMM Computer Communication Review, - 33(2), April 2003. - - [Sar03] P. Sarolahti. Congestion Control on Spurious TCP - Retransmission Timeouts. In Proceedings of IEEE Globecom - 2003, San Francisco, CA, USA. December 2003. - - [SL03] Y. Swami and K. Le, "DCLOR: De-correlated Loss Recovery - using SACK Option for Spurious Timeouts", work in progress, - September 2003. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Sarolahti & Kojo Experimental [Page 14] - -RFC 4138 Forward RTO-Recovery August 2005 - - -Appendix A: Scenarios - - This section discusses different scenarios where RTOs occur and how - the basic F-RTO algorithm performs in those scenarios. The - interesting scenarios are: a sudden delay triggering retransmission - timeout, loss of a retransmitted packet during fast recovery, link - outage causing the loss of several packets, and packet reordering. A - performance evaluation with a more thorough analysis on a real - implementation of F-RTO is given in [SKR03]. - -A.1. Sudden Delay - - The main motivation behind the F-RTO algorithm is to improve TCP - performance when a delay spike triggers a spurious retransmission - timeout. The example below illustrates the segments and - acknowledgments transmitted by the TCP end hosts when a spurious - timeout occurs, but no packets are lost. For simplicity, delayed - acknowledgments are not used in the example. The example below - applies the Eifel Response Algorithm [LG04] after detecting a - spurious timeout. - - ... - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 1. <---------------------------- ACK 5 - 2. SEND 10 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 3. <---------------------------- ACK 6 - 4. SEND 11 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 5. | - [delay] - | - [RTO] - [F-RTO step (1)] - 6. SEND 6 ----------------------------> - (cwnd = 6, ssthresh = 3, FlightSize = 6) - ---> - 7. <---------------------------- ACK 7 - [F-RTO step (2b)] - 8. SEND 12 ----------------------------> - 9. SEND 13 ----------------------------> - (cwnd = 7, ssthresh = 3, FlightSize = 7) - ---> - 10. <---------------------------- ACK 8 - [F-RTO step (3b)] - [SpuriousRecovery <- SPUR_TO] - (cwnd = 7, ssthresh = 6, FlightSize = 6) - - - - -Sarolahti & Kojo Experimental [Page 15] - -RFC 4138 Forward RTO-Recovery August 2005 - - - 11. SEND 14 ----------------------------> - (cwnd = 7, ssthresh = 6, FlightSize = 7) - 12. <---------------------------- ACK 9 - 13. SEND 15 ----------------------------> - (cwnd = 7, ssthresh = 6, FlightSize = 7) - 14. <---------------------------- ACK 10 - 15. SEND 16 ----------------------------> - (cwnd = 7, ssthresh = 6, FlightSize = 7) - ... - - When a sudden delay (long enough to trigger timeout) occurs at step - 5, the TCP sender retransmits the first unacknowledged segment (step - 6). The next ACK covers the RTO retransmission because the - originally transmitted segment 6 arrived at the receiver, and the TCP - sender continues by sending two new data segments (steps 8, 9). Note - that on F-RTO steps (1) and (2b), congestion window and FlightSize - are not yet reset because in the case of spurious timeout, the - segments sent before the timeout are still in the network. However, - the sender should still be equally aggressive toward conventional - TCP. Because the second acknowledgment arriving after the RTO - retransmission acknowledges data that was not retransmitted due to - timeout (step 10), the TCP sender declares the timeout to be spurious - and continues by sending new data on the next acknowledgments. Also, - the congestion control state is reversed, as required by the Eifel - Response Algorithm. - -A.2. Loss of a Retransmission - - If a retransmitted segment is lost, the only way to retransmit it is - to wait for the timeout to trigger the retransmission. Once the - segment is successfully received, the receiver usually acknowledges - several segments at once, because other segments in the same window - have been successfully delivered before the retransmission arrives at - the receiver. The example below shows a scenario where - retransmission (of segment 6) is lost, as well as a later segment - (segment 9) in the same window. The limited transmit [ABF01] or SACK - TCP [MMFR96] enhancements are not in use in this example. - - ... - (cwnd = 6, ssthresh < 6, FlightSize = 6) - - - 1. <---------------------------- ACK 5 - 2. SEND 10 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 3. <---------------------------- ACK 6 - 4. SEND 11 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - - - -Sarolahti & Kojo Experimental [Page 16] - -RFC 4138 Forward RTO-Recovery August 2005 - - - 5. <---------------------------- ACK 6 - 6. <---------------------------- ACK 6 - 7. <---------------------------- ACK 6 - 8. SEND 6 --------------X - (cwnd = 6, ssthresh = 3, FlightSize = 6) - - 9. <---------------------------- ACK 6 - 10. SEND 12 ----------------------------> - (cwnd = 7, ssthresh = 3, FlightSize = 7) - 11. <---------------------------- ACK 6 - 12. SEND 13 ----------------------------> - (cwnd = 8, ssthresh = 3, FlightSize = 8) - [RTO] - 13. SEND 6 ----------------------------> - (cwnd = 8, ssthresh = 2, FlightSize = 8) - 14. <---------------------------- ACK 9 - [F-RTO step (2b)] - 15. SEND 14 ----------------------------> - 16. SEND 15 ----------------------------> - (cwnd = 7, ssthresh = 2, FlightSize = 7) - 17. <---------------------------- ACK 9 - [F-RTO step (3a)] - [SpuriousRecovery <- FALSE] - (cwnd = 3, ssthresh = 2, FlightSize = 7) - 18. SEND 9 ----------------------------> - 19. SEND 10 ----------------------------> - 20. SEND 11 ----------------------------> - ... - - In the example above, segment 6 is lost and the sender retransmits it - after three duplicate ACKs in step 8. However, the retransmission is - also lost, and the sender has to wait for the RTO to expire before - retransmitting it again. Because the first ACK following the RTO - retransmission acknowledges the RTO retransmission (step 14), the - sender transmits two new segments. The second ACK in step 17 does - not acknowledge any previously unacknowledged data. Therefore, the - F-RTO sender enters the slow start and sets cwnd to 3 * MSS. The - congestion window can be set to three segments, because two round- - trips have elapsed after the retransmission timeout. Finally, the - receiver acknowledges all segments transmitted prior to entering - recovery and the sender can continue transmitting new data in - congestion avoidance. - - - - - - - - - -Sarolahti & Kojo Experimental [Page 17] - -RFC 4138 Forward RTO-Recovery August 2005 - - -A.3. Link Outage - - The example below illustrates the F-RTO behavior when 4 consecutive - packets are lost in the network causing the TCP sender to fall back - to RTO recovery. Limited transmit and SACK are not used in this - example. - - ... - (cwnd = 6, ssthresh < 6, FlightSize = 6) - - 1. <---------------------------- ACK 5 - 2. SEND 10 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 3. <---------------------------- ACK 6 - 4. SEND 11 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 5. <---------------------------- ACK 6 - | - | - [RTO] - 6. SEND 6 ----------------------------> - (cwnd = 6, ssthresh = 3, FlightSize = 6) - 7. <---------------------------- ACK 7 - [F-RTO step (2b)] - 8. SEND 12 ----------------------------> - 9. SEND 13 ----------------------------> - (cwnd = 7, ssthresh = 3, FlightSize = 7) - 10. <---------------------------- ACK 7 - [F-RTO step (3a)] - [SpuriousRecovery <- FALSE] - (cwnd = 3, ssthresh = 3, FlightSize = 7) - 11. SEND 7 ----------------------------> - 12. SEND 8 ----------------------------> - 13. SEND 9 ----------------------------> - - Again, F-RTO sender transmits two new segments (steps 8 and 9) after - the RTO retransmission is acknowledged. Because the next ACK does - not acknowledge any data that was not retransmitted after the - retransmission timeout (step 10), the F-RTO sender proceeds with - conventional recovery and slow start retransmissions. - -A.4. Packet Reordering - - Because F-RTO modifies the TCP sender behavior only after a - retransmission timeout and it is intended to avoid unnecessary - retransmissions only after spurious timeout, we limit the discussion - on the effects of packet reordering on F-RTO behavior to the cases - where it occurs immediately after the retransmission timeout. When - - - -Sarolahti & Kojo Experimental [Page 18] - -RFC 4138 Forward RTO-Recovery August 2005 - - - the TCP receiver gets an out-of-order segment, it generates a - duplicate ACK. If the TCP sender implements the basic F-RTO - algorithm, this may prevent the sender from detecting a spurious - timeout. - - However, if the TCP sender applies the SACK-enhanced F-RTO, it is - possible to detect a spurious timeout when packet reordering occurs. - Below, we illustrate the behavior of SACK-enhanced F-RTO when segment - 8 arrives before segments 6 and 7, and segments starting from segment - 6 are delayed in the network. In this example the TCP sender reduces - the congestion window and slow start threshold in response to - spurious timeout. - - ... - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 1. <---------------------------- ACK 5 - 2. SEND 10 ----------------------------> - (cwnd = 6, ssthresh < 6, FlightSize = 6) - 3. <---------------------------- ACK 6 - 4. SEND 11 ----------------------------> - 5. | - [delay] - | - [RTO] - 6. SEND 6 ----------------------------> - (cwnd = 6, ssthresh = 3, FlightSize = 6) - ---> - 7. <---------------------------- ACK 6 - [SACK 8] - [SACK F-RTO stays in step 2] - 8. ---> - 9. <---------------------------- ACK 7 - [SACK 8] - [SACK F-RTO step (2b)] - 10. SEND 12 ----------------------------> - 11. SEND 13 ----------------------------> - (cwnd = 7, ssthresh = 3, FlightSize = 7) - 12. ---> - 13. <---------------------------- ACK 9 - [SACK F-RTO step (3b)] - [SpuriousRecovery <- SPUR_TO] - (cwnd = 7, ssthresh = 6, FlightSize = 6) - 14. SEND 14 ----------------------------> - (cwnd = 7, ssthresh = 6, FlightSize = 7) - 15. <---------------------------- ACK 10 - 16. SEND 15 ----------------------------> - ... - - - - -Sarolahti & Kojo Experimental [Page 19] - -RFC 4138 Forward RTO-Recovery August 2005 - - - After RTO expires and the sender retransmits segment 6 (step 6), the - receiver gets segment 8 and generates duplicate ACK with SACK for - segment 8. In response to the acknowledgment, the TCP sender does - not send anything but stays in F-RTO step 2. Because the next - acknowledgment advances the cumulative ACK point (step 9), the sender - can transmit two new segments according to SACK-enhanced F-RTO. The - next segment acknowledges new data between 7 and 11 that was not - acknowledged earlier (segment 7), so the F-RTO sender declares the - timeout spurious. - -Appendix B: SACK-enhanced F-RTO and Fast Recovery - - We believe that a slightly modified, SACK-enhanced F-RTO algorithm - can be used to detect spurious timeouts also when RTO expires while - an earlier loss recovery is underway. However, there are issues that - need to be considered if F-RTO is applied in this case. - - In step 3, the original SACK-based F-RTO algorithm requires that an - ACK acknowledges previously unacknowledged non-retransmitted data - between SND.UNA and send_high. If RTO expires during earlier - (SACK-based) loss recovery, the F-RTO sender must use only - acknowledgments for non-retransmitted segments transmitted before the - SACK-based loss recovery started. This means that in order to - declare timeout spurious, the TCP sender must receive an - acknowledgment for non-retransmitted segment between SND.UNA and - RecoveryPoint in algorithm step 3. RecoveryPoint is defined in - conservative SACK-recovery algorithm [BAFW03], and it is set to - indicate the highest segment transmitted so far when SACK-based loss - recovery begins. In other words, if the TCP sender receives - acknowledgment for a segment that was transmitted more than one RTO - ago, it can declare the timeout spurious. Defining an efficient - algorithm for checking these conditions remains a future work item. - - When spurious timeout is detected according to the rules given above, - it may be possible that the response algorithm needs to consider this - case separately, for example, in terms of which segments to - retransmit after RTO expires, and whether it is safe to revert the - congestion control parameters. This is considered a topic for future - research. - - - - - - - - - - - - -Sarolahti & Kojo Experimental [Page 20] - -RFC 4138 Forward RTO-Recovery August 2005 - - -Appendix C: Discussion of Window-Limited Cases - - When the advertised window limits the transmission of two new - previously unsent segments, or there are no new data to send, it is - recommended in F-RTO algorithm step (2b) that the TCP sender continue - with the conventional RTO recovery algorithm. The disadvantage is - that the sender may continue unnecessary retransmissions due to - possible spurious timeout. This section briefly discusses the - options that can potentially improve performance when transmitting - previously unsent data is not possible. - - - The TCP sender could reserve an unused space of a size of one or - two segments in the advertised window to ensure the use of - algorithms such as F-RTO or Limited Transmit [ABF01] in window- - limited situations. On the other hand, while doing this, the TCP - sender should ensure that the window of outstanding segments is - large enough for proper utilization of the available pipe. - - - Use additional information if available, e.g., TCP timestamps with - the Eifel Detection algorithm, for detecting a spurious timeout. - However, Eifel detection may yield different results from F-RTO - when ACK losses and an RTO occur within the same round-trip time - [SKR03]. - - - Retransmit data from the tail of the retransmission queue and - continue with step 3 of the F-RTO algorithm. It is possible that - the retransmission will be made unnecessarily. Thus, this option - is not encouraged, except for hosts that are known to operate in an - environment that is prone to spurious timeouts. On the other hand, - with this method it is possible to limit unnecessary - retransmissions due to spurious timeout to one retransmission. - - - Send a zero-sized segment below SND.UNA, similar to TCP Keep-Alive - probe, and continue with step 3 of the F-RTO algorithm. Because - the receiver replies with a duplicate ACK, the sender is able to - detect whether the timeout was spurious from the incoming - acknowledgment. This method does not send data unnecessarily, but - it delays the recovery by one round-trip time in cases where the - timeout was not spurious. Therefore, this method is not - encouraged. - - - In receiver-limited cases, send one octet of new data, regardless - of the advertised window limit, and continue with step 3 of the - F-RTO algorithm. It is possible that the receiver will have free - buffer space to receive the data by the time the segment has - propagated through the network, in which case no harm is done. If - the receiver is not capable of receiving the segment, it rejects - the segment and sends a duplicate ACK. - - - -Sarolahti & Kojo Experimental [Page 21] - -RFC 4138 Forward RTO-Recovery August 2005 - - -Authors' Addresses - - Pasi Sarolahti - Nokia Research Center - P.O. Box 407 - FIN-00045 NOKIA GROUP - Finland - - Phone: +358 50 4876607 - EMail: pasi.sarolahti@nokia.com - http://www.cs.helsinki.fi/u/sarolaht/ - - - Markku Kojo - University of Helsinki - Department of Computer Science - P.O. Box 68 - FIN-00014 UNIVERSITY OF HELSINKI - Finland - - Phone: +358 9 191 51305 - EMail: kojo@cs.helsinki.fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Sarolahti & Kojo Experimental [Page 22] - -RFC 4138 Forward RTO-Recovery August 2005 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2005). - - This document is subject to the rights, licenses and restrictions - contained in BCP 78, and except as set forth therein, the authors - retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; nor does it represent that it has - made any independent effort to identify any such rights. Information - on the procedures with respect to rights in RFC documents can be - found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use of - such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository at - http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights that may cover technology that may be required to implement - this standard. Please address the information to the IETF at ietf- - ipr@ietf.org. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - -Sarolahti & Kojo Experimental [Page 23] - diff --git a/ext/picotcp/RFC/rfc4278.txt b/ext/picotcp/RFC/rfc4278.txt deleted file mode 100644 index 377314d..0000000 --- a/ext/picotcp/RFC/rfc4278.txt +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - -Network Working Group S. Bellovin -Request for Comments: 4278 AT&T Labs Research -Category: Informational A. Zinin - Alcatel - January 2006 - - - Standards Maturity Variance Regarding the TCP MD5 Signature Option - (RFC 2385) and the BGP-4 Specification - -Status of This Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2006). - -Abstract - - The IETF Standards Process requires that all normative references for - a document be at the same or higher level of standardization. RFC - 2026 section 9.1 allows the IESG to grant a variance to the standard - practices of the IETF. This document explains why the IESG is - considering doing so for the revised version of the BGP-4 - specification, which refers normatively to RFC 2385, "Protection of - BGP Sessions via the TCP MD5 Signature Option". RFC 2385 will remain - at the Proposed Standard level. - -1. Introduction - - The IETF Standards Process [RFC2026] requires that all normative - references for a document be at the same or higher level of - standardization. RFC 2026 section 9.1 allows the IESG to grant a - variance to the standard practices of the IETF. Pursuant to that, it - is considering publishing the updated BGP-4 specification [RFC4271] - as Draft Standard, despite the normative reference to [RFC2385], - "Protection of BGP Sessions via the TCP MD5 Signature Option". RFC - 2385 will remain a Proposed Standard. (Note that although the title - of [RFC2385] includes the word "signature", the technology described - in it is commonly known as a Message Authentication Code or MAC, and - should not be confused with digital signature technologies.) - - [RFC2385], which is widely implemented, is the only transmission - security mechanism defined for BGP-4. Other possible mechanisms, - such as IPsec [RFC2401] and TLS [RFC2246], are rarely, if ever, used - - - -Bellovin & Zinin Informational [Page 1] - -RFC 4278 Standards Maturity Variance: RFC 2385 and BGP-4 January 2006 - - - for this purpose. Given the long-standing requirement for security - features in protocols, it is not possible to advance BGP-4 without a - mandated security mechanism. - - The conflict of maturity levels between specifications would normally - be resolved by advancing the specification being referred to along - the standards track, to the level of maturity that the referring - specification needs to achieve. However, in the particular case - considered here, the IESG believes that [RFC2385], though adequate - for BGP deployments at this moment, is not strong enough for general - use, and thus should not be progressed along the standards track. In - this situation, the IESG believes that variance procedure should be - used to allow the updated BGP-4 specification to be published as - Draft Standard. - - The following sections of the document give detailed explanations of - the statements above. - -2. Draft Standard Requirements - - The requirements for Proposed Standards and Draft Standards are given - in [RFC2026]. For Proposed Standards, [RFC2026] warns that: - - Implementors should treat Proposed Standards as immature - specifications. It is desirable to implement them in order to - gain experience and to validate, test, and clarify the - specification. However, since the content of Proposed Standards - may be changed if problems are found or better solutions are - identified, deploying implementations of such standards into a - disruption-sensitive environment is not recommended. - - In other words, it is considered reasonable for flaws to be - discovered in Proposed Standards. - - The requirements for Draft Standards are higher: - - A Draft Standard must be well-understood and known to be quite - stable, both in its semantics and as a basis for developing an - implementation. - - In other words, any document that has known deficiencies should not - be promoted to Draft Standard. - - - - - - - - - -Bellovin & Zinin Informational [Page 2] - -RFC 4278 Standards Maturity Variance: RFC 2385 and BGP-4 January 2006 - - -3. The TCP MD5 Signature Option - - [RFC2385], despite its 1998 publication date, describes a Message - Authentication Code (MAC) that is considerably older. It utilizes a - technique known as a "keyed hash function", using MD5 [RFC1321] as - the hash function. When the original code was developed, this was - believed to be a reasonable technique, especially if the key was - appended (rather than prepended) to the data being protected. But - cryptographic hash functions were never intended for use as MACs, and - later cryptanalytic results showed that the construct was not as - strong as originally believed [PV1, PV2]. Worse yet, the underlying - hash function, MD5, has shown signs of weakness [Dobbertin, Wang]. - Accordingly, the IETF community has adopted Hashed Message - Authentication Code (HMAC) [RFC2104], a scheme with provable security - properties, as its standard MAC. - - Beyond that, [RFC2385] does not include any sort of key management - technique. Common practice is to use a password as a shared secret - between pairs of sites, but this is not a good idea [RFC3562]. - - Other problems are documented in [RFC2385] itself, including the lack - of a type code or version number, and the inability of systems using - this scheme to accept certain TCP resets. - - Despite the widespread deployment of [RFC2385] in BGP deployments, - the IESG has thus concluded that it is not appropriate for use in - other contexts. [RFC2385] is not suitable for advancement to Draft - Standard. - -4. Usage Patterns for RFC 2385 - - Given the above analysis, it is reasonable to ask why [RFC2385] is - still used for BGP. The answer lies in the deployment patterns - peculiar to BGP. - - BGP connections inherently tend to travel over short paths. Indeed, - most external BGP links are one hop. Although internal BGP sessions - are usually multi-hop, the links involved are generally inhabited - only by routers rather than general-purpose computers; general- - purpose computers are easier for attackers to use as TCP hijacking - tools [Joncheray]. - - Also, BGP peering associations tend to be long-lived and static. By - contrast, many other security situations are more dynamic. - - This is not to say that such attacks cannot happen. (If they - couldn't happen at all, there would be no point to any security - measures.) Attackers could divert links at layers 1 or 2, or they - - - -Bellovin & Zinin Informational [Page 3] - -RFC 4278 Standards Maturity Variance: RFC 2385 and BGP-4 January 2006 - - - could (in some situations) use Address Resolution Protocol (ARP) - spoofing at Ethernet-based exchange points. Still, on balance, BGP - is employed in an environment that is less susceptible to this sort - of attack. - - There is another class of attack against which BGP is extremely - vulnerable: false route advertisements from more than one autonomous - system (AS) hop away. However, neither [RFC2385] nor any other - transmission security mechanism can block such attacks. Rather, a - scheme such as S-BGP [Kent] would be needed. - -5. LDP - - The Label Distribution Protocol (LDP) [RFC3036] also uses [RFC2385]. - Deployment practices for LDP are very similar to those of BGP: LDP - connections are usually confined within a single autonomous system - and most frequently span a single link between two routers. This - makes the LDP threat environment very similar to BGP's. Given this, - and a considerable installed base of LDP in service provider - networks, we are not deprecating [RFC2385] for use with LDP. - -6. Security Considerations - - The IESG believes that the variance described here will not adversely - affect the security of the Internet. - -7. Conclusions - - Given the above analysis, the IESG is persuaded that waiving the - prerequisite requirement is the appropriate thing to do. [RFC2385] - is clearly not suitable for Draft Standard. Other existing - mechanisms, such as IPsec, would do its job better. However, given - the current operational practices in service provider networks at the - moment -- and in particular the common use of long-lived standard - keys, [RFC3562] notwithstanding -- the marginal benefit of such - schemes in this situation would be low, and not worth the transition - effort. We would prefer to wait for a security mechanism tailored to - the major threat environment for BGP. - -8. Informative References - - [Dobbertin] H. Dobbertin, "The Status of MD5 After a Recent Attack", - RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996. - - [Joncheray] Joncheray, L. "A Simple Active Attack Against TCP." - Proceedings of the Fifth Usenix Unix Security Symposium, - 1995. - - - - -Bellovin & Zinin Informational [Page 4] - -RFC 4278 Standards Maturity Variance: RFC 2385 and BGP-4 January 2006 - - - [Kent] Kent, S., C. Lynn, and K. Seo. "Secure Border Gateway - Protocol (Secure-BGP)." IEEE Journal on Selected Areas - in Communications, vol. 18, no. 4, April, 2000, pp. - 582-592. - - [RFC3562] Leech, M., "Key Management Considerations for the TCP - MD5 Signature Option", RFC 3562, July 2003. - - [PV1] B. Preneel and P. van Oorschot, "MD-x MAC and building - fast MACs from hash functions," Advances in Cryptology - --- Crypto 95 Proceedings, Lecture Notes in Computer - Science Vol. 963, D. Coppersmith, ed., Springer-Verlag, - 1995. - - [PV2] B. Preneel and P. van Oorschot, "On the security of two - MAC algorithms," Advances in Cryptology --- Eurocrypt 96 - Proceedings, Lecture Notes in Computer Science, U. - Maurer, ed., Springer-Verlag, 1996. - - [RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm ", RFC - 1321, April 1992. - - [RFC2026] Bradner, S., "The Internet Standards Process -- Revision - 3", BCP 9, RFC 2026, October 1996. - - [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: - Keyed-Hashing for Message Authentication", RFC 2104, - February 1997. - - [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", - RFC 2246, January 1999. - - [RFC2385] Heffernan, A., "Protection of BGP Sessions via the TCP - MD5 Signature Option", RFC 2385, August 1998. - - [RFC2401] Kent, S. and R. Atkinson, "Security Architecture for the - Internet Protocol", RFC 2401, November 1998. - - [RFC3036] Andersson, L., Doolan, P., Feldman, N., Fredette, A., - and B. Thomas, "LDP Specification", RFC 3036, January - 2001. - - [RFC4271] Rekhter, Y., Li, T., and S. Hares, Eds., "A Border - Gateway Protocol 4 (BGP-4)", RFC 4271, January 2006. - - [Wang] Wang, X. and H. Yu, "How to Break MD5 and Other Hash - Functions." Proceedings of Eurocrypt '05, 2005. - - - - -Bellovin & Zinin Informational [Page 5] - -RFC 4278 Standards Maturity Variance: RFC 2385 and BGP-4 January 2006 - - -Authors' Addresses - - Steven M. Bellovin - Department of Computer Science - Columbia University - 1214 Amsterdam Avenue, M.C. 0401 - New York, NY 10027-7003 - - Phone: +1 212-939-7149 - EMail: bellovin@acm.org - - - Alex Zinin - Alcatel - 701 E Middlefield Rd - Mountain View, CA 94043 - - EMail: zinin@psg.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Bellovin & Zinin Informational [Page 6] - -RFC 4278 Standards Maturity Variance: RFC 2385 and BGP-4 January 2006 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2006). - - This document is subject to the rights, licenses and restrictions - contained in BCP 78, and except as set forth therein, the authors - retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Intellectual Property - - The IETF takes no position regarding the validity or scope of any - Intellectual Property Rights or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; nor does it represent that it has - made any independent effort to identify any such rights. Information - on the procedures with respect to rights in RFC documents can be - found in BCP 78 and BCP 79. - - Copies of IPR disclosures made to the IETF Secretariat and any - assurances of licenses to be made available, or the result of an - attempt made to obtain a general license or permission for the use of - such proprietary rights by implementers or users of this - specification can be obtained from the IETF on-line IPR repository at - http://www.ietf.org/ipr. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights that may cover technology that may be required to implement - this standard. Please address the information to the IETF at - ietf-ipr@ietf.org. - -Acknowledgement - - Funding for the RFC Editor function is provided by the IETF - Administrative Support Activity (IASA). - - - - - - - -Bellovin & Zinin Informational [Page 7] - diff --git a/ext/picotcp/docs/user_manual/README.md b/ext/picotcp/docs/user_manual/README.md deleted file mode 100644 index 3f33e3c..0000000 --- a/ext/picotcp/docs/user_manual/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Downloading the manual ----------------------- - -With every git commit, we rebuild the documentation and make the [user_doc.pdf](http://162.13.84.104/user_doc.pdf) file (click to download) publicly available. - -If for some reason, you're looking for an older version of the documentation, please check out the wanted commit in git, and compile the manual as described below. - -Compiling the manual --------------------- - -The picoTCP user manual is written in LaTeX, which needs to be compiled to get a readable version. -First and foremost you need the compiler and some packages: -* sudo apt-get install texlive -* sudo apt-get install texlive-latex-extra - -Now, cd into docs/user_manual and do -* ./build.sh - -A user_doc.pdf should be generated in the current directory - diff --git a/ext/picotcp/docs/user_manual/build.sh b/ext/picotcp/docs/user_manual/build.sh deleted file mode 100755 index 56eaf31..0000000 --- a/ext/picotcp/docs/user_manual/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -pdflatex user_doc.tex && pdflatex user_doc.tex && pdflatex user_doc.tex diff --git a/ext/picotcp/docs/user_manual/chap_api_aodv.tex b/ext/picotcp/docs/user_manual/chap_api_aodv.tex deleted file mode 100644 index 02171ea..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_aodv.tex +++ /dev/null @@ -1,42 +0,0 @@ -\section{Ad-hoc On-Demand Distance Vector Routing (AODV)} - - -AODV is a reactive routing protocol for mobile ad-hoc networks -(MANETs). Its best fit are especially ultra-low power radio networks, -or those RF topologies where sporadic traffic between a small specific set -of nodes is foreseen. -In order to create a route, one node must explicitly start the communication -towards a remote node, and the route is created ad-hoc upon the demand -for a specific network path. -AODV guarantees that the traffic generated by each node in order to create -and maintain routes is kept as low as possible. - -\subsection{pico\_aodv\_add} - -\subsubsection*{Description} -This function will add the target device to the AODV mechanism on the machine, -meaning that it will be possible to advertise and collect routing information -using Ad-hoc On-Demand Distance Vector Routing, as described in RFC3561, through the -target device. - -In order to use multiple devices in the AODV system, this function needs to be called -multiple times, once per device. - -\subsubsection*{Function prototype} -\texttt{pico\_aodv\_add(struct pico\_device *dev);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the device is successfully added. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_aodv_add(dev); - -\end{verbatim} - diff --git a/ext/picotcp/docs/user_manual/chap_api_dhcp_c.tex b/ext/picotcp/docs/user_manual/chap_api_dhcp_c.tex deleted file mode 100644 index 940d157..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_dhcp_c.tex +++ /dev/null @@ -1,170 +0,0 @@ -\section{DHCP client} - -% Short description/overview of module functions -A DHCP client for obtaining a dynamic IP address. DHCP is supported on multiple interfaces. - - -\subsection{pico\_dhcp\_initiate\_negotiation} - -\subsubsection*{Description} -Initiate a DHCP negotiation. The user passes a callback-function, which will be executed on DHCP success or failure. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_dhcp_initiate_negotiation(struct pico_device *device, - void (*callback)(void *cli, int code), uint32_t *xid); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{device} - the device on which a negotiation should be started. -\item \texttt{callback} - the function which is executed on success or failure. This function can be called multiple times. F.e.: initially DHCP succeeded, then the DHCP server is removed long enough from the network for the lease to expire, later the server is added again to the network. The callback is called 3 times: first with code \texttt{PICO\_DHCP\_SUCCESS}, then with \texttt{PICO\_DHCP\_RESET} and finally with \texttt{PICO\_DHCP\_SUCCESS}. The callback may be called before \texttt{pico\_dhcp\_initiate\_negotiation} has returned, f.e. in case of failure to open a socket. The callback has two parameters: -\begin{itemize}[noitemsep] -\item \texttt{cli} - the identifier of the negotiation -\item \texttt{code} - the id indicating success or failure, see further -\end{itemize} -\item \texttt{xid} - transaction id of the negotiation. Is set on \texttt{PICO\_DHCP\_SUCCESS}, 0 otherwise. -\end{itemize} - -\subsubsection*{Possible DHCP codes} -\begin{itemize}[noitemsep] -\item \texttt{PICO\_DHCP\_SUCCESS} - DHCP succeeded, the user can start using the assigned address, which can be obtained by calling \texttt{pico\_dhcp\_get\_address}. -\item \texttt{PICO\_DHCP\_ERROR} - an error occurred. DHCP is unable to recover from this error. \texttt{pico$\_$err} is set appropriately. -\item \texttt{PICO\_DHCP\_RESET} - DHCP was unable to renew its lease, and the lease expired. The user must immediately stop using the previously assigned IP, and wait for DHCP to obtain a new lease. DHCP will automatically start negotiations again. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 on success, -1 otherwise. - -\subsubsection*{Errors} % ORGANIZE -All errors are reported through the callback-function described above. -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available % pico_socket_sendto -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\item \texttt{PICO$\_$ERR$\_$EPROTONOSUPPORT} - protocol not supported % pico_socket_open -\item \texttt{PICO$\_$ERR$\_$ENETUNREACH} - network unreachable -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument % pico_socket_bind -\item \texttt{PICO$\_$ERR$\_$ENXIO} - no such device or address -\item \texttt{PICO$\_$ERR$\_$EOPNOTSUPP} - operation not supported on socket -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -pico_dhcp_initiate_negotiation(dev, &callback_dhcpclient, &xid); -\end{verbatim} - -\subsection{pico\_dhcp\_client\_abort} - -\subsubsection*{Description} -Cancel the ongoing negotiation. To be used if the operation of obtaining an IP address from a remote DHCP server needs to be aborted, before the callback has been triggered. - -\subsubsection*{Function prototype} -\texttt{struct pico\_ip4 pico\_dhcp\_client\_abort(uint32\_t xid);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] - \item \texttt{xid} - the transaction id returned from the call \texttt{pico\_dhcp\_initiate\_negotiation}. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 on success, -1 otherwise (i.e. the XID could not be found in the list of ongoing transactions). - - -\subsection{pico\_dhcp\_get\_identifier} - -\subsubsection*{Description} -Get the identifier needed to pass to all other \texttt{pico\_dhcp} functions. This function should only be called after a callback occurred with code \texttt{PICO\_DHCP\_SUCCESS}. - -\subsubsection*{Function prototype} -\texttt{void *pico\_dhcp\_get\_identifier(uint32\_t xid);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{xid} - transaction id of the negotiation. -\end{itemize} - -\subsubsection*{Return value} -\texttt{void *} - pointer to the identifier. - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -void *cli = pico_dhcp_get_identifier(xid); -\end{verbatim} - - -\subsection{pico\_dhcp\_get\_address} - -\subsubsection*{Description} -Get the address that was assigned through DHCP. This function should only be called after a callback occurred with code \texttt{PICO\_DHCP\_SUCCESS}. - -\subsubsection*{Function prototype} -\texttt{struct pico\_ip4 pico\_dhcp\_get\_address(void *cli);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{cli} - the identifier that was provided by the callback on \texttt{PICO\_DHCP\_SUCCESS}. -\end{itemize} - -\subsubsection*{Return value} -\texttt{struct pico\_ip4} - the address that was assigned. - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_ip4 address = pico_dhcp_get_address(cli); -\end{verbatim} - - -\subsection{pico\_dhcp\_get\_gateway} - -\subsubsection*{Description} -Get the address of the gateway that was assigned through DHCP. This function should -only be called after a callback occurred with code \texttt{PICO\_DHCP\_SUCCESS}. - -\subsubsection*{Function prototype} -\texttt{struct pico\_ip4 pico\_dhcp\_get\_gateway(void *cli);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{cli} - the identifier that was provided by the callback on \texttt{PICO\_DHCP\_SUCCESS}. -\end{itemize} - -\subsubsection*{Return value} -\begin{itemize}[noitemsep] -\item \texttt{struct pico\_ip4} - the address of the gateway that should be used. -\end{itemize} - -\subsection{pico\_dhcp\_get\_nameserver} - -\subsubsection*{Description} -Get the address of the first or the second nameserver that was assigned through DHCP. -This function should only be called after a callback occurred with code \texttt{PICO\_DHCP\_SUCCESS}. - -\subsubsection*{Function prototype} -\texttt{struct pico\_ip4 pico\_dhcp\_get\_nameserver(void *cli, int index);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{cli} - the identifier that was provided by the callback on \texttt{PICO\_DHCP\_SUCCESS}. -\item \texttt{index} - the indes of the domain name server received. Can be either "0" or "1". -\end{itemize} - -\subsubsection*{Return value} -\begin{itemize}[noitemsep] -\item \texttt{struct pico\_ip4} - the address of the nameserver that should be used. On failure, e.g. an invalid index was passed, it returns "255.255.255.255". If the IP address of the DNS has not been set, it may return INADDR\_ANY. -\end{itemize} - - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_ip4 gateway = pico_dhcp_get_gateway(cli); -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_api_dhcp_d.tex b/ext/picotcp/docs/user_manual/chap_api_dhcp_d.tex deleted file mode 100644 index 671fff3..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_dhcp_d.tex +++ /dev/null @@ -1,71 +0,0 @@ -\section{DHCP server} - -% Short description/overview of module functions - - -\subsection{pico\_dhcp\_server\_initiate} - -\subsubsection*{Description} -This function starts a simple DHCP server. - -\subsubsection*{Function prototype} -\texttt{int pico\_dhcp\_server\_initiate(struct pico\_dhcpd\_settings *settings);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{settings} - a pointer to a struct \texttt{pico\_dhcpd\_settings}, in which the following members matter to the user : -\begin{itemize}[noitemsep] -\item \texttt{struct pico\_ip4 my\_ip} - the IP address of the device performing DHCP. Only IPs of this network will be served. -\item \texttt{uint32\_t pool\_start} - the lowest host number that may be assigned, defaults to 100 if not provided. -\item \texttt{uint32\_t pool\_end} - the highest host number that may be assigned, defaults to 254 if not provided. -\item \texttt{uint32\_t lease\_time} - the advertised lease time in seconds, defaults to 120 if not provided. -\end{itemize} -\end{itemize} - -\subsubsection*{Return value} -On successful startup of the dhcp server, 0 is returned. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -%everything from : -%pico_socket_open -\item PICO$\_$ERR$\_$EPROTONOSUPPORT - protocol not supported -\item PICO$\_$ERR$\_$ENETUNREACH - network unreachable -%pico_socket_bind -\item PICO$\_$ERR$\_$EINVAL - invalid argument -\item PICO$\_$ERR$\_$ENXIO - no such device or address -\end{itemize} - -\subsection{pico\_dhcp\_server\_destroy} - -\subsubsection*{Description} -This function stops a previously started DHCP server on the given device. - -\subsubsection*{Function prototype} -\texttt{int pico\_dhcp\_server\_destroy(struct pico\_device *dev);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device}, to identify a previously started DHCP server that must be terminated. -\end{itemize} - -\subsubsection*{Return value} -On success, 0 is returned. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item PICO$\_$ERR$\_$ENOENT - there was no DHCP server running on the given device. -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_dhcpd_settings s = { }; - -s.my_ip.addr = long_be(0x0a280001); /* 10.40.0.1 */ - -pico_dhcp_server_initiate(&s); -\end{verbatim} - - diff --git a/ext/picotcp/docs/user_manual/chap_api_dns_c.tex b/ext/picotcp/docs/user_manual/chap_api_dns_c.tex deleted file mode 100644 index 8d4a51b..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_dns_c.tex +++ /dev/null @@ -1,115 +0,0 @@ -\section{DNS client} - -% Short description/overview of module functions - - -\subsection{pico$\_$dns$\_$client$\_$nameserver} - -\subsubsection*{Description} -Function to add or remove nameservers. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{ns} - Pointer to the address of the name server. -\item \texttt{flag} - Flag to indicate addition or removal (see further). -\end{itemize} - -\subsubsection*{Flags} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$DNS$\_$NS$\_$ADD} - to add a nameserver -\item \texttt{PICO$\_$DNS$\_$NS$\_$DEL} - to remove a nameserver -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the nameserver operation has succeeded. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_dns_client_nameserver(&addr_ns, PICO_DNS_NS_ADD); -ret = pico_dns_client_nameserver(&addr_ns, PICO_DNS_NS_DEL); -\end{verbatim} - - - -\subsection{pico$\_$dns$\_$client$\_$getaddr} - -\subsubsection*{Description} -Function to translate an url text string to an internet host address IP. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_dns_client_getaddr(const char *url, void (*callback)(char *ip, void *arg), - void *arg); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{url} - Pointer to text string containing url text string (e.g. www.google.com). -\item \texttt{callback} - Callback function, returning the internet host address IP and the provided argument. The returned string has to be freed by the user. -\item \texttt{arg} - Pointer to an identifier for the request. The pointer is returned in the callback. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the request is sent. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_dns_client_getaddr("www.google.com", cb_getaddr, &identifier); -\end{verbatim} - - - -\subsection{pico$\_$dns$\_$client$\_$getname} - -\subsubsection*{Description} -Function to translate an internet host address IP to an url text string. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_dns_client_getname(const char *ip, void (*callback)(char *url, void *arg), - void *arg); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{ip} - Pointer to text string containing an internet host address IP (e.g. 8.8.4.4) -\item \texttt{callback} - Callback function, receiving the url text string. Note: the returned string has to be freed by the user. -\item \texttt{arg} - Pointer to an identifier for the request. The pointer is returned in the callback. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the request is sent. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_dns_client_getname("8.8.4.4", cb_getname, &identifier); -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_api_dns_sd.tex b/ext/picotcp/docs/user_manual/chap_api_dns_sd.tex deleted file mode 100644 index 871ec2c..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_dns_sd.tex +++ /dev/null @@ -1,85 +0,0 @@ -\section{DNS SD client} - -% Short description/overview of module functions -With this module DNS-SD services can be registered on the network to allow Zero Configuration Networking on the device. This is merely a small layer on top of Multicast DNS. - -\subsection{pico$\_$dns$\_$sd$\_$init} - -\subsubsection*{Description} -Just calls pico$\_$mdns$\_$init in its turn to initialise the mDNS-module. See 'pico$\_$mdns$\_$init' for more information. - - -\subsection{pico$\_$dns$\_$sd$\_$register$\_$service} - -\subsubsection*{Description} -Registers the service with a certain name and type on the network via Multicast DNS. -\subsubsection*{Function prototype} -\begin{verbatim} -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); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{name} - Instance-name of the service. Use a descriptive name for it but not longer than 63 characters. -\item \texttt{type} - The type of the service. For all the possible service types see: \url{http://www.dns-sd.org/servicetypes.html} -\item \texttt{port} - The portnumber on which the service runs. -\item \texttt{txt$\_$data} - Pointer to vector with key-value pairs to insert into the TXT record to give additional information about the service. Use the 'PICO$\_$DNS$\_$SD$\_$KV$\_$VECTOR$\_$DECLARE'-macro to declare a vector for key-value-pairs. This vector will be destroyed when the function returns since there's no need in keeping the contents. -\item \texttt{ttl} - TTL of the service on the network before it needs to be reconfirmed. In seconds. -\item \texttt{callback} - Callback function that gets called when the service is successfully registered on the network. -\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 when the module successfully started registering the service, something else on failure. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -PICO_DNS_SD_KV_VECTOR_DECLARE(dictionary); -pico_dns_sd_register_service("Printer 2nd Floor", "_printer._sub._http._tcp", 80, \\ -&dictionary, 240, ®_cb, NULL); -\end{verbatim} - - -\subsection{pico$\_$dns$\_$sd$\_$kv$\_$vector$\_$add} - -\subsubsection*{Description} -Add a key-value pair the a key-value pair vector. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value ); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{vector} - Pointer to vector to add the pair to. Declare a key-value vector with the 'PICO$\_$DNS$\_$SD$\_$KV$\_$VECTOR$\_$DECLARE'-macro. -\item \texttt{key} - Key of the pair. Cannot be NULL. -\item \texttt{value} - Value of the pair. can be NULL, empty ("") or filled ("value"). -\end{itemize} - -\subsubsection*{Return value} -Returns 0 when the pair is added successfully, something else on failure. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -PICO_DNS_SD_KV_VECTOR_DECLARE(dictionary); -pico_dns_sd_kv_vector_add(&dictionary, "pass", "1234"); -pico_dns_sd_kv_vector_add(&dictionary, "color", NULL); -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_api_igmp.tex b/ext/picotcp/docs/user_manual/chap_api_igmp.tex deleted file mode 100644 index dba1abd..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_igmp.tex +++ /dev/null @@ -1,42 +0,0 @@ -\section{IGMP} - -% Short description/overview of module functions -This module allows the user to join and leave ipv4 multicast groups. The module is based on the IGMP version 3 protocol and it's backwards compatible with version 2. Version 1 is not supported. -The IGMP module is completly driven from socket calls (\ref{socket:setoption}) and non of the IGMP application interface functions should be called by the user. If however, by any reason, it's necessary for the user to do this, the following function call is provided: - -\subsection{pico\_igmp\_state\_change} - -\subsubsection*{Description} -Change the state of the host to Non-member, Idle member or Delaying member. - -\subsubsection*{Function prototype} -\begin{verbatim} -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) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{mcast\_link} - the link on which that multicast group should be joined. -\item \texttt{mcast\_group} - the address of the multicast group you want to join. -\item \texttt{filter\_mode} - the kind of source filtering, if applied. -\item \texttt{\_MCASTFilter} - list of multicast sources on which source filtering might be applied. -\item \texttt{state} - the prefered new state. -\end{itemize} - -\subsubsection*{Errors} -In case of failure, -1 is returned, and the value of pico$\_$err -is set as follows: - -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - Invalid argument provided -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - Not enough space -\item \texttt{PICO$\_$ERR$\_$EPROTONOSUPPORT} - Invalid protocol (or protocol version) found on the link -\item \texttt{PICO$\_$ERR$\_$EFAULT} - Internal error -\end{itemize} - -%\subsubsection*{Example} - -%\subsubsection*{Errors} - -%\subsubsection*{Example} diff --git a/ext/picotcp/docs/user_manual/chap_api_ipfilter.tex b/ext/picotcp/docs/user_manual/chap_api_ipfilter.tex deleted file mode 100644 index 8faf71e..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_ipfilter.tex +++ /dev/null @@ -1,89 +0,0 @@ -\section{IP Filter} - -% Short description/overview of module functions -This module allows the user to add and remove filters. The user can filter packets based on interface, protocol, outgoing address, outgoing netmask, incomming address, incomming netmask, outgoing port, incomming port, priority and type of service. There are four types of filters: ACCEPT, PRIORITY, REJECT, DROP. When creating a PRIORITY filter, it is necessary to give a priority value in a range between '-10' and '10', '0' as default priority. - - -\subsection{pico$\_$ipv4$\_$filter$\_$add} - -\subsubsection*{Description} -Function to add a filter. - -\subsubsection*{Function prototype} -\begin{verbatim} -int 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); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - interface to be filtered -\item \texttt{proto} - protocol to be filtered -\item \texttt{out$\_$addr} - outgoing address to be filtered -\item \texttt{out$\_$addr$\_$netmask} - outgoing address-netmask to be filtered -\item \texttt{in$\_$addr} - incomming address to be filtered -\item \texttt{in$\_$addr$\_$netmask} - incomming address-netmask to be filtered -\item \texttt{out$\_$port} - outgoing port to be filtered -\item \texttt{in$\_$port} - incomming port to be filtered -\item \texttt{priority} - priority to assign on the marked packet -\item \texttt{tos} - type of service to be filtered -\item \texttt{action} - type of action for the filter: ACCEPT, PRIORITY, REJECT and DROP. ACCEPT, filters all packets selected by the filter. PRIORITY is not yet implemented. REJECT drops all packets and send an ICMP message 'Packet Filtered' (Communication Administratively Prohibited). DROP will discard the packet silently. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the filter$\_$id from the generated filter. This id must be used when deleting the filter. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Example} -\begin{verbatim} -/* block all incoming traffic on port 5555 */ -filter_id = pico_ipv4_filter_add(NULL, 6, NULL, NULL, NULL, NULL, 0, 5555, - 0, 0, FILTER_REJECT); -\end{verbatim} - -\subsubsection*{Errors} - -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - - -\subsection{pico$\_$ipv4$\_$filter$\_$del} - -\subsubsection*{Description} -Function to delete a filter. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_filter_del(int filter_id) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{filter$\_$id} - the id of the filter you want to delete. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} - -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EPERM} - operation not permitted -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_filter_del(filter_id); -\end{verbatim} - - -%\subsubsection*{Parameters} -%\subsubsection*{Return value} -%\subsubsection*{Errors} -%\subsubsection*{Example} - diff --git a/ext/picotcp/docs/user_manual/chap_api_ipv4.tex b/ext/picotcp/docs/user_manual/chap_api_ipv4.tex deleted file mode 100644 index 88c64ee..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_ipv4.tex +++ /dev/null @@ -1,561 +0,0 @@ -\section{IPv4 functions} - -% Short description/overview of module functions - -\subsection{pico$\_$ipv4$\_$to$\_$string} - -\subsubsection*{Description} -Convert the internet host address IP to a string in IPv4 dotted-decimal notation. -The result is stored in the char array that ipbuf points to. The given IP address argument must be in network order (i.e. 0xC0A80101 becomes 192.168.1.1). - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_to_string(char *ipbuf, const uint32_t ip); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{ipbuf} - Char array to store the result in. -\item \texttt{ip} - Internet host address in integer notation. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the conversion was successful. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_to_string(buf, ip); -\end{verbatim} - - - -\subsection{pico$\_$string$\_$to$\_$ipv4} - -\subsubsection*{Description} -Convert the IPv4 dotted-decimal notation into binary form. The result is stored in the -\texttt{int} that IP points to. Little endian or big endian is not taken into account. -The address supplied in \texttt{ipstr} can have one of the following -forms: a.b.c.d, a.b.c or a.b. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{ipstr} - Pointer to the IP string. -\item \texttt{ip} - Int pointer to store the result in. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the conversion was successful. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_string_to_ipv4(buf, *ip); -\end{verbatim} - - -\subsection{pico$\_$ipv4$\_$valid$\_$netmask} - -\subsubsection*{Description} -Check if the provided mask if valid. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_valid_netmask(uint32_t mask); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{mask} - The netmask in integer notation. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the netmask in CIDR notation is returned if the netmask is valid. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_valid_netmask(netmask); -\end{verbatim} - - -\subsection{pico$\_$ipv4$\_$is$\_$unicast} - -\subsubsection*{Description} -Check if the provided address is unicast or multicast. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_is_unicast(uint32_t address); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address in integer notation. -\end{itemize} - -\subsubsection*{Return value} -Returns 1 if unicast, 0 if multicast. - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_is_unicast(address); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$source$\_$find} - -\subsubsection*{Description} -Find the source IP for the link associated to the specified destination. -This function will use the currently configured routing table to identify the link that would be used to transmit any traffic directed to the given IP address. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_ip4 *pico_ipv4_source_find(struct pico_ip4 *dst); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as \texttt{struct pico$\_$ip4}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the source IP as \texttt{struct pico$\_$ip4}. -If the source can not be found, \texttt{NULL} is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -src = pico_ipv4_source_find(dst); -\end{verbatim} - - - - -\subsection{pico$\_$ipv4$\_$link$\_$add } - -\subsubsection*{Description} -Add a new local device dev inteface, f.e. eth0, with IP address 'address' and netmask 'netmask'. A device may have more than one link configured, i.e. to access multiple networks on the same link. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, -struct pico_ip4 netmask); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - Local device. -\item \texttt{address} - Pointer to the internet host address as \texttt{struct pico$\_$ip4}. -\item \texttt{netmask} - Netmask of the address. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$ENETUNREACH} - network unreachable -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_link_add(dev, address, netmask); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$link$\_$del} - -\subsubsection*{Description} -Remove the link associated to the local device that was previously configured, corresponding to the IP address 'address'. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - Local device. -\item \texttt{address} - Pointer to the internet host address as \texttt{struct pico$\_$ip4}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_link_del(dev, address); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$link$\_$find} - -\subsubsection*{Description} -Find the local device associated to the local IP address 'address'. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the internet host address as \texttt{struct pico$\_$ip4}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the local device. -On error, \texttt{NULL} is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENXIO} - no such device or address -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -dev = pico_ipv4_link_find(address); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$nat$\_$enable} - -\subsubsection*{Description} -This function enables NAT functionality on the passed IPv4 link. -Forwarded packets from an internal network will have the public IP address from the passed link -and a translated port number for transmission on the external network. -Usual operation requires at least one additional link for the internal network, -which is used as a gateway for the internal hosts. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_nat_enable(struct pico_ipv4_link *link) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{link} - Pointer to a link \texttt{pico$\_$ipv4$\_$link}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_nat_enable(&external_link); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$nat$\_$disable} - -\subsubsection*{Description} -Disables the NAT functionality. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_nat_disable(void); -\end{verbatim} - -%\subsubsection*{Parameters} - -\subsubsection*{Return value} -Always returns 0. - -%\subsubsection*{Errors} -%\subsubsection*{Example} - - -\subsection{pico$\_$ipv4$\_$port$\_$forward} - -\subsubsection*{Description} -This function adds or deletes a rule in the IP forwarding table. Internally in the stack, -a one-direction NAT entry will be made. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, -struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, -uint8_t persistant) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{pub$\_$addr} - Public IP address, must be identical to the address of the external link. -\item \texttt{pub$\_$port} - Public port to be translated. -\item \texttt{priv$\_$addr} - Private IP address of the host on the internal network. -\item \texttt{priv$\_$port} - Private port of the host on the internal network. -\item \texttt{proto} - Protocol identifier, see supported list below. -\item \texttt{persistant} - Option for function call: create \texttt{PICO$\_$IPV4$\_$FORWARD$\_$ADD} (= 1) \\ -or delete \texttt{PICO$\_$IPV4$\_$FORWARD$\_$DEL} (= 0). -\end{itemize} - -\subsubsection*{Protocol list} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$PROTO$\_$ICMP4} -\item \texttt{PICO$\_$PROTO$\_$TCP} -\item \texttt{PICO$\_$PROTO$\_$UDP} -\end{itemize} - -\subsubsection*{Return value} -On success, this call 0 after a succesfull entry of the forward rule. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - not succesfull, try again -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_port_forward(ext_link_addr, ext_port, host_addr, -host_port, PICO_PROTO_UDP, 1); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$route$\_$add} - -\subsubsection*{Description} -Add a new route to the destination IP address from the local device link, f.e. eth0. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, -struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as \texttt{struct pico$\_$ip4}. -\item \texttt{netmask} - Netmask of the address. If zeroed, the call assumes the meaning of adding a default gateway. -\item \texttt{gateway} - Gateway of the address network. If zeroed, no gateway will be associated to this route, and the traffic towards the destination will be simply forwarded towards the given device. -\item \texttt{metric} - Metric for this route. -\item \texttt{link} - Local device interface. If a valid gateway is specified, this parameter is not mandatory, otherwise \texttt{NULL} can be used. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. -%if the route already exists or no memory could be allocated. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENETUNREACH} - network unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_route_add(dst, netmask, gateway, metric, link); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$route$\_$del} - -\subsubsection*{Description} -Remove the route to the destination IP address from the local device link, f.e. etho0. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, -struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as struct \texttt{pico$\_$ip4}. -\item \texttt{netmask} - Netmask of the address. -\item \texttt{gateway} - Gateway of the address network. -\item \texttt{metric} - Metric of the route. -\item \texttt{link} - Local device interface. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the route is found. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv4_route_del(dst, netmask, gateway, metric, link); -\end{verbatim} - - - -\subsection{pico$\_$ipv4$\_$route$\_$get$\_$gateway} - -\subsubsection*{Description} -This function gets the gateway address for the given destination IP address, if set. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as struct \texttt{pico$\_$ip4}. -\end{itemize} - -\subsubsection*{Return value} -On success the gateway address is returned. -On error a \texttt{null} address is returned (\texttt{0.0.0.0}) and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -gateway_addr = pico_ip4 pico_ipv4_route_get_gateway(&dest_addr) -\end{verbatim} - - -\subsection{pico$\_$icmp4$\_$ping} - -\subsubsection*{Description} -This function sends out a number of ping echo requests and checks if the replies are received correctly. -The information from the replies is passed to the callback function after a succesfull reception. -If a timeout expires before a reply is received, the callback is called with the error condition. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, -void (*cb)(struct pico_icmp4_stats *)); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dst} - Pointer to the destination internet host address as text string -\item \texttt{count} - Number of pings going to be send -\item \texttt{interval} - Time between two transmissions (in ms) -\item \texttt{timeout} - Timeout period untill reply received (in ms) -\item \texttt{size} - Size of data buffer in bytes -\item \texttt{cb} - Callback for ICMP ping -\end{itemize} - -\subsubsection*{Data structure \texttt{struct pico$\_$icmp4$\_$stats}} -\begin{verbatim} -struct pico_icmp4_stats -{ - struct pico_ip4 dst; - unsigned long size; - unsigned long seq; - unsigned long time; - unsigned long ttl; - int err; -}; -\end{verbatim} -With \textbf{err} values: -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$PING$\_$ERR$\_$REPLIED} (value 0) -\item \texttt{PICO$\_$PING$\_$ERR$\_$TIMEOUT} (value 1) -\item \texttt{PICO$\_$PING$\_$ERR$\_$UNREACH} (value 2) -\item \texttt{PICO$\_$PING$\_$ERR$\_$PENDING} (value 0xFFFF) -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns a positive number, which is the ID of the ping operation just started. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -id = pico_icmp4_ping(dst_addr, 30, 10, 100, 1000, callback); -\end{verbatim} - - -\subsection{pico$\_$icmp4$\_$ping$\_$abort} - -\subsubsection*{Description} -This function aborts an ongoing ping operation that has previously started using pico$\_$icmp4$\_$ping(). - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_icmp4_ping_abort(int id); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] - \item \texttt{id} - identification number for the ping operation. This has been returned by \texttt{pico$\_$icmp4$\_$ping()} and it is intended to distinguish the operation to be cancelled. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_icmp4_ping_abort(id); -\end{verbatim} - diff --git a/ext/picotcp/docs/user_manual/chap_api_ipv6.tex b/ext/picotcp/docs/user_manual/chap_api_ipv6.tex deleted file mode 100644 index 49868b1..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_ipv6.tex +++ /dev/null @@ -1,533 +0,0 @@ -\section{IPv6 functions} - -% Short description/overview of module functions - -\subsection{pico$\_$ipv6$\_$to$\_$string} - -\subsubsection*{Description} -Convert the internet host address IP to a string in IPv6 colon:hex notation. -The result is stored in the char array that ipbuf points to. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{ipbuf} - Char array to store the result in. -\item \texttt{ip} - Internet host address in unsigned byte array notation of lenght 16. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the conversion was successful. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_to_string(buf, ip); -\end{verbatim} - -\subsection{pico$\_$string$\_$to$\_$ipv6} - -\subsubsection*{Description} -Convert the IPv6 colon:hex notation into binary form. The result is stored in the -\texttt{int} that IP points to. -The address supplied in \texttt{ipstr} can have one of the default forms for IPv6 address -description, including at most one abbreviation skipping zeroed fields using "::" - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_string_to_ipv6(const char *ipstr, uint8_t *ip); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{ipstr} - Pointer to the IP string. -\item \texttt{ip} - Int pointer to store the result in. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the conversion was successful. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_string_to_ipv6("fe80::1", *ip); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$unicast} - -\subsubsection*{Description} -Check if the provided address is unicast or multicast. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_unicast(struct pico_ip6 *a); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} - -\subsubsection*{Return value} -Returns 1 if unicast, 0 if multicast. - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_unicast(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$multicast} -\subsubsection*{Description} -Check if the provided address is a valid Internet multicast address, i.e. it belongs to the range ff00::/8. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_multicast(struct pico_ip6 *a); -\end{verbatim} -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} -\subsubsection*{Return value} -Returns 1 if a multicast Internet address has been provided. -%\subsubsection*{Errors} -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_multicast(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$global} - -\subsubsection*{Description} -Check if the provided address is a valid Internet global address, i.e. it belongs to the range 2000::/3. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_global(struct pico_ip6 *a); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} - -\subsubsection*{Return value} -Returns 1 if a global Internet address has been provided. - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_global(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$uniquelocal} - -\subsubsection*{Description} -Check if the provided address is a valid Internet uniquelocal address, i.e. it belongs to the range fc00::/7. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_uniquelocal(struct pico_ip6 *a); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} - -\subsubsection*{Return value} -Returns 1 if a uniquelocal Internet address has been provided. - -%\subsubsection*{Errors} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_uniquelocal(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$sitelocal} -\subsubsection*{Description} -Check if the provided address is a valid Internet sitelocal address, i.e. it belongs to the range fec0::/10. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_sitelocal(struct pico_ip6 *a); -\end{verbatim} -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} -\subsubsection*{Return value} -Returns 1 if a sitelocal Internet address has been provided. -%\subsubsection*{Errors} -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_sitelocal(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$linklocal} -\subsubsection*{Description} -Check if the provided address is a valid Internet linklocal address, i.e. it belongs to the range fe80::/10. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_linklocal(struct pico_ip6 *a); -\end{verbatim} -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} -\subsubsection*{Return value} -Returns 1 if a linklocal Internet address has been provided. -%\subsubsection*{Errors} -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_linklocal(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$localhost} -\subsubsection*{Description} -Check if the provided address is a valid Internet localhost address, i.e. it is "::1". -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_localhost(struct pico_ip6 *a); -\end{verbatim} -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} -\subsubsection*{Return value} -Returns 1 if a localhost Internet address has been provided. -%\subsubsection*{Errors} -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_localhost(address); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$is$\_$undefined} -\subsubsection*{Description} -Check if the provided address is a valid Internet undefined address, i.e. it is "::0". -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_is_undefined(struct pico_ip6 *a); -\end{verbatim} -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Internet host address. -\end{itemize} -\subsubsection*{Return value} -Returns 1 if the Internet address provided describes ANY host. -%\subsubsection*{Errors} -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_is_undefined(address); -\end{verbatim} - - -\subsection{pico$\_$ipv6$\_$source$\_$find} - -\subsubsection*{Description} -Find the source IP for the link associated to the specified destination. -This function will use the currently configured routing table to identify the link that would be used to transmit any traffic directed to the given IP address. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_ip6 *pico_ipv6_source_find(struct pico_ip6 *dst); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as \texttt{struct pico$\_$ip6}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the source IP as \texttt{struct pico$\_$ip6}. -If the source can not be found, \texttt{NULL} is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -src = pico_ipv6_source_find(dst); -\end{verbatim} - - - - -\subsection{pico$\_$ipv6$\_$link$\_$add } - -\subsubsection*{Description} -Add a new local device dev inteface, f.e. eth0, with IP address 'address' and netmask 'netmask'. A device may have more than one link configured, i.e. to access multiple networks on the same link. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, -struct pico_ip6 netmask); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - Local device. -\item \texttt{address} - Pointer to the internet host address as \texttt{struct pico$\_$ip6}. -\item \texttt{netmask} - Netmask of the address. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$ENETUNREACH} - network unreachable -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_link_add(dev, address, netmask); -\end{verbatim} - - - -\subsection{pico$\_$ipv6$\_$link$\_$del} - -\subsubsection*{Description} -Remove the link associated to the local device that was previously configured, corresponding to the IP address 'address'. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - Local device. -\item \texttt{address} - Pointer to the internet host address as \texttt{struct pico$\_$ip6}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_link_del(dev, address); -\end{verbatim} - - - -\subsection{pico$\_$ipv6$\_$link$\_$find} - -\subsubsection*{Description} -Find the local device associated to the local IP address 'address'. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_device *pico_ipv6_link_find(struct pico_ip6 *address); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the internet host address as \texttt{struct pico$\_$ip6}. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the local device. -On error, \texttt{NULL} is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENXIO} - no such device or address -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -dev = pico_ipv6_link_find(address); -\end{verbatim} - - - - -\subsection{pico$\_$ipv6$\_$route$\_$add} - -\subsubsection*{Description} -Add a new route to the destination IP address from the local device link, f.e. eth0. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, -struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as \texttt{struct pico$\_$ip6}. -\item \texttt{netmask} - Netmask of the address. If zeroed, the call assumes the meaning of adding a default gateway. -\item \texttt{gateway} - Gateway of the address network. If zeroed, no gateway will be associated to this route, and the traffic towards the destination will be simply forwarded towards the given device. -\item \texttt{metric} - Metric for this route. -\item \texttt{link} - Local device interface. If a valid gateway is specified, this parameter is not mandatory, otherwise \texttt{NULL} can be used. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0. On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. -%if the route already exists or no memory could be allocated. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENETUNREACH} - network unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_route_add(dst, netmask, gateway, metric, link); -\end{verbatim} - - - -\subsection{pico$\_$ipv6$\_$route$\_$del} - -\subsubsection*{Description} -Remove the route to the destination IP address from the local device link, f.e. etho0. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_ipv6_route_del(struct pico_ip6 address, struct pico_ip6 netmask, -struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as struct \texttt{pico$\_$ip6}. -\item \texttt{netmask} - Netmask of the address. -\item \texttt{gateway} - Gateway of the address network. -\item \texttt{metric} - Metric of the route. -\item \texttt{link} - Local device interface. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the route is found. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_ipv6_route_del(dst, netmask, gateway, metric, link); -\end{verbatim} - - - -\subsection{pico$\_$ipv6$\_$route$\_$get$\_$gateway} - -\subsubsection*{Description} -This function gets the gateway address for the given destination IP address, if set. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_ip6 pico_ipv6_route_get_gateway(struct pico_ip6 *addr) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{address} - Pointer to the destination internet host address as struct \texttt{pico$\_$ip6}. -\end{itemize} - -\subsubsection*{Return value} -On success the gateway address is returned. -On error a \texttt{null} address is returned (\texttt{0.0.0.0}) and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -gateway_addr = pico_ip6 pico_ipv6_route_get_gateway(&dest_addr) -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$dev$\_$routing$\_$enable} - -\subsubsection*{Description} -Enable IPv6 Routing messages through the specified interface. On a picoTCP IPv6 machine, -when routing is enabled, all possible routes to other links are advertised to the target interfaces. -This allows the hosts connected to the target interface to use the picoTCP IPv6 machine as a router -towards public IPv6 addresses configured on other interfaces, or reachable through known gateways. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_ip6 pico_ipv6_dev_routing_enable(struct pico_device *dev) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - Pointer to the target device struct \texttt{pico$\_$device}. -\end{itemize} - -\subsubsection*{Return value} -On success, zero is returned. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Example} -\begin{verbatim} -retval = pico_ipv6_dev_routing_enable(eth1); -\end{verbatim} - -\subsection{pico$\_$ipv6$\_$dev$\_$routing$\_$disable} - -\subsubsection*{Description} -Enable IPv6 Routing messages through the specified interface. On a picoTCP IPv6 machine, -when routing is enabled, all possible routes to other links are advertised to the target interface. -This function will stop advertising reachable routes to public IPv6 addresses configured on other -interfaces, or reachable through known gateways. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_ip6 pico_ipv6_dev_routing_disable(struct pico_device *dev) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - Pointer to the target device struct \texttt{pico$\_$device}. -\end{itemize} - -\subsubsection*{Return value} -On success, zero is returned. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Example} -\begin{verbatim} -retval = pico_ipv6_dev_routing_disable(eth1); -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_api_mdns.tex b/ext/picotcp/docs/user_manual/chap_api_mdns.tex deleted file mode 100644 index 6437831..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_mdns.tex +++ /dev/null @@ -1,235 +0,0 @@ -\section{MDNS client} - -% Short description/overview of module functions -This module can register DNS resource records on the network via Multicast DNS as either \textbf{\emph{shared}} or \textbf{\emph{unique}} records. Unique records are, as the name implies, unique on the network (the record-name and -type combination is unique) and one single host has claimed the ownership of them. Shared records are records that are not unique on the network, which means multiple hosts can register records with the same record-name and -type combination. For more information on shared and unique resource record sets, see RFC6762. - -Unique records are, as it should, defended when somebody else tries to claim the same unique records. When hosts detect such a defense of another host while registering their own records, the conflict will be resolved by choosing another name for the records and another attempt is made to register those new records. - -This module only supplies the mechanisms of record registration and resolving on the network, it doesn't parses the contents of them, that's up to the application. - -\subsection{pico$\_$mdns$\_$init} - -\subsubsection*{Description} -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 network. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_mdns_init( const char *hostname, - struct pico_ip4 address, - void (*callback)(pico_mdns_rtree *, char *, void *), - void *arg ); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{hostname} - Hostname to register for this machine. Should end with \'.local\'. -\item \texttt{address} - IPv4-address of this machines interface to generate a hostname record from. -\item \texttt{cb$\_$initialised} - Callback-function that is called when the initialisation process is done. This will also get called when asynchronous conflicts occur for successfully registered records during run-time. The mDNS-record tree contains the registered records, the char-buffer contains the registered hostname and the void-pointer contains the passed argument. -\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 when the module is properly initialised and the host started registering the hostname. Returns something else went the host failed initialising the module or registering the hostname. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -pico_mdns_init("host.local", address, &mdns_init_callback, NULL); -\end{verbatim} - - -\subsection{pico$\_$mdns$\_$get$\_$hostname} - -\subsubsection*{Description} -Get the current hostname for this machine. - -\subsubsection*{Function prototype} -\begin{verbatim} -const char * pico_mdns_get_hostname( void ); -\end{verbatim} - -\subsubsection*{Return value} -Returns the current hostname for this machine when the module is initialised, returns NULL when the module is not initialised. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -char *url = pico_mdns_get_hostname(); -\end{verbatim} - - -\subsection{pico$\_$mdns$\_$set$\_$hostname} - -\subsubsection*{Description} -Tries to claim a 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 succeeded. Init-callback specified when initialising the module will be called when the hostname-record is successfully registered. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_mdns_tryclaim_hostname( const char *url, void *arg ); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{url} - URL to set the hostname to. Should end with \'.local\'. -\item \texttt{arg} - Argument for init-callback supplied by user. This can be used if you want to pass some variable into your callback function. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 when the host started registering the hostname-record successfully, returns something else when it didn't succeed. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_mdns_tryclaim_hostname("device.local", NULL); -\end{verbatim} - - -\subsection{pico$\_$mdns$\_$claim} - -\subsubsection*{Description} -Claims all different mDNS records in a tree in a single API-call. All records in the mDNS record-tree are registered in a single new claim-session. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_mdns_claim( pico_mdns_rtree record_tree, - void (*callback)(pico_mdns_rtree *, char *, void *), - void *arg ); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{record$\_$tree} - mDNS record-tree with records to register on the network via Multicast DNS. Can contain \textbf{\emph{unique records}} as well as \textbf{\emph{shared records}}. Declare a mDNS record-tree with the macro 'PICO$\_$MDNS$\_$RTREE$\_$DECLARE(name)', which is actually just a pico$\_$tree-struct, with a comparing-function already set. Records can be added with the preprocessor macro 'PICO$\_$MDNS$\_$RTREE$\_$ADD(pico$\_$mdns$\_$rtree *, struct pico$\_$mdns$\_$record *)'. To create mDNS records see 'pico$\_$mdns$\_$record$\_$create'. -\item \texttt{callback} - Callback function that gets called when \textbf{\emph{ALL}} records in the tree are successfully registered on the network. Records in the returned tree can differ from records originally registered due to conflict-resolution and such. -\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 when the host started registering the record successfully, returns something else when it didn't succeed. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -... -PICO_MDNS_RTREE_DECLARE(rtree); -PICO_MDNS_RTREE_ADD(&rtree, &record); -int ret = pico_mdns_claim(rtree, &claimed_cb, NULL); -\end{verbatim} - - -\subsection{pico$\_$mdns$\_$getrecord} - -\subsubsection*{Description} -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. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_mdns_getrecord( const char *url, uint16_t type, - void (*callback)(pico_mdns_rtree *, char *, void *), - void *arg ); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{url} - URL of the DNS name to query records for. -\item \texttt{type} - DNS type of the records to query for on the network. -\item \texttt{callback} - Callback to call when records are found or answers to the query are received. This functions can get called multiple times when multiple answers are possible (e.g. with shared records). It's up to the application to aggregate all these received answers, this is possible with a static variable of the type pico$\_$mdns$\_$rtree. -\item \texttt{arg} - Argument for callback supplied by user. This can be used if you want to pass some variable into your callback function. -\end{itemize} - -\subsubsection*{Return value} -Returns 0 when the host started querying for these records successfully or the records are found in the cache. Returns something else when it didn't succeed. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_mdns_getrecord("_ipp._tcp.local", PICO_DNS_TYPE_PTR, &query_cb, NULL); -\end{verbatim} - - -\subsection{pico$\_$mdns$\_$record$\_$create} - -\subsubsection*{Description} -Creates a single standalone mDNS resource record with given name, type and data to register on the network. - -\subsubsection*{Function prototype} -\begin{verbatim} -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 ); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{url} - DNS resource record name in URL format. Will be converted to DNS name notation format. -\item \texttt{$\_$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. -\item \texttt{datalen} - The exact length in bytes of the $\_$rdata-buffer. If data of record should contain a DNS name (f.e. with PICO$\_$DNS$\_$TYPE$\_$PTR), datalen needs to be pico$\_$dns$\_$strlen($\_$rdata). -\item \texttt{rtype} - DNS type of the resource record to be. -\item \texttt{ttl} - TTL of the resource record to be when registered on the network. In seconds. -\item \texttt{flags} - With this parameter, you can specify a record as either a shared record or a unique record with respectively PICO$\_$MDNS$\_$RECORD$\_$SHARED- or PICO$\_$MDNS$\_$RECORD$\_$UNIQUE-preprocessor defines. Records are by default registered as unique. -\end{itemize} - -\subsubsection*{Return value} -Returns a pointer to the newly created record on success, returns NULL on failure. \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -pico_ip4 ip = 0; -pico_string_to_ipv4("10.10.0.5", &(ip.addr)); -struct pico_mdns_record *record = pico_mdns_record_create("foo.local", - &(ip.addr), - PICO_SIZE_IP4, - PICO_DNS_TYPE_ANY, - 120, - PICO_MDNS_RECORD_UNIQUE); -\end{verbatim} - - -\subsection{IS$\_$HOSTNAME$\_$RECORD} - -\subsubsection*{Description} -The initialisation-callback can get called multiple times during run-time due to \emph{passive conflict detection}. A passive conflict occurs for unique records when a faulty Multicast DNS-responder doesn't apply conflict resolution after an occurred conflict. A passive conflict can also occur when a peer registers a \textbf{\emph{shared}} record with the same name and type combination as a \textbf{\emph{unique}} record that the local host already successfully registered on the network. Because of that, shared records have priority over unique records, so unfortunately the local host has to apply the conflict resolution-mechanism to it's earlier uniquely verified record. To be able to notify the application of an updated unique record, the callback gets called given in the initialisation-function. But since that callback maybe parses the returned records as the hostname-records and this isn't necessarily the case when a passive conflict occurs, a mechanism is needed to differ hostname-records from other records. This preprocessor-macro allows this. - -\subsubsection*{Function prototype} -\begin{verbatim} -IS_HOSTNAME_RECORD(record) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{record} - mDNS resource record -\end{itemize} - -\subsubsection*{Return value} -Returns 1 when this record is a hostname record, returns 0 when it's not or when given pointer is a NULL pointer. \ No newline at end of file diff --git a/ext/picotcp/docs/user_manual/chap_api_mld.tex b/ext/picotcp/docs/user_manual/chap_api_mld.tex deleted file mode 100644 index b66aca3..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_mld.tex +++ /dev/null @@ -1,42 +0,0 @@ -\section{MLD} - -% Short description/overview of module functions -This module allows the user to join and leave ipv6 multicast groups. The module is based on the MLD version 2 protocol and it's backwards compatible with version 1. -The MLD module is completly driven from socket calls (\ref{socket:setoption}) and non of the MLD application interface functions should be called by the user. If however, by any reason, it's necessary for the user to do this, the following function call is provided: - -\subsection{pico\_mld\_state\_change} - -\subsubsection*{Description} -Change the state of the host to Non-listener, Idle listener or Delaying listener. - -\subsubsection*{Function prototype} -\begin{verbatim} -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) -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{mcast\_link} - the link on which that multicast group should be joined. -\item \texttt{mcast\_group} - the address of the multicast group you want to join. -\item \texttt{filter\_mode} - the kind of source filtering, if applied. -\item \texttt{\_MCASTFilter} - list of multicast sources on which source filtering might be applied. -\item \texttt{state} - the prefered new state. -\end{itemize} - -\subsubsection*{Errors} -In case of failure, -1 is returned, and the value of pico$\_$err -is set as follows: - -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - Invalid argument provided -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - Not enough space -\item \texttt{PICO$\_$ERR$\_$EPROTONOSUPPORT} - Invalid protocol (or protocol version) found on the link -\item \texttt{PICO$\_$ERR$\_$EFAULT} - Internal error -\end{itemize} - -%\subsubsection*{Example} - -%\subsubsection*{Errors} - -%\subsubsection*{Example} diff --git a/ext/picotcp/docs/user_manual/chap_api_olsr.tex b/ext/picotcp/docs/user_manual/chap_api_olsr.tex deleted file mode 100644 index 424fc35..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_olsr.tex +++ /dev/null @@ -1,49 +0,0 @@ -\section{Optimized Link State Routing (OLSR) Module} - - -OLSR is a proactive routing protocol for mobile ad-hoc networks -(MANETs). It is well suited to large and dense mobile -networks, as the optimization achieved using the MPRs works well in -this context. The larger and more dense a network, the more -optimization can be achieved as compared to the classic link state -algorithm. OLSR uses hop-by-hop routing, i.e., each node uses its -local information to route packets. - -OLSR is well suited for networks, where the traffic is random and -sporadic between a larger set of nodes rather than being almost -exclusively between a small specific set of nodes. As a proactive -protocol, OLSR is also suitable for scenarios where the communicating -pairs change over time: no additional control traffic is generated in -this situation since routes are maintained for all known destinations -at all times. -- cfr. RFC3626 - - -\subsection{pico\_olsr\_add} - -\subsubsection*{Description} -This function will add the target device to the OLSR mechanism on the machine, -meaning that it will be possible to advertise and collect routing information -using Optimized Link State Routing protocol, as described in RFC3626, through the -target device. - -In order to use multiple devices in the OLSR system, this function needs to be called -multiple times, once per device. - -\subsubsection*{Function prototype} -\texttt{pico\_olsr\_add(struct pico\_device *dev);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the device is successfully added. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_olsr_add(dev); - -\end{verbatim} - diff --git a/ext/picotcp/docs/user_manual/chap_api_ppp.tex b/ext/picotcp/docs/user_manual/chap_api_ppp.tex deleted file mode 100644 index 112cf47..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_ppp.tex +++ /dev/null @@ -1,257 +0,0 @@ -\section{Point-to-Point Protocol (PPP)} - -PPP consists in a family of data-link protocols, providing link control, -configuration and authentication over a point-to-point link. In a connected -embedded system, it is often used to access dial-up modems over serial lines. - -This module supports GSM modem configuration by implementing part of ETSI TS 127 007. - -From the picoTCP perspective, each PPP capable device may be abstracted into its own instance -that can be created using \texttt{pico\_ppp\_create}. - -Any GSM/GPRS/3G/HSDPA module, exporting a non-blocking serial interface, such as SPI or UART, -can be connected to the ppp device abstraction, using \texttt{pico\_ppp\_set\_serial\_read}, -\texttt{pico\_ppp\_set\_serial\_write}, \texttt{pico\_ppp\_set\_serial\_set\_speed}. - -Once the physical interface is attached, the access to the remote access point gateway -can be configured using \texttt{pico\_ppp\_set\_apn}, \texttt{pico\_ppp\_set\_username} and -\texttt{pico\_ppp\_set\_password}. - -When the interface is configured, the connection may be established using -\texttt{pico\_ppp\_connect}. Even if the peer disconnects, the connection will be brought up -again automatically afterwords. - -To interrupt the connection and stop the automatic reconnection, \texttt{pico\_ppp\_disconnect} -can be called. - -\subsection{pico\_ppp\_create} - -\subsubsection*{Description} -This function will create a new device association to be used with the ppp driver. The driver -must then afterwards be associated with lower-level serial functions in order to be used. - -\subsubsection*{Function prototype} -\texttt{struct pico\_device *pico\_ppp\_create(void);} - -\subsubsection*{Return value} -A new pico\_device is allocated and returned if the device is successfully created. - -\subsubsection*{Example} -\begin{verbatim} - -ppp = pico_ppp_create(); - -\end{verbatim} - -\subsection{pico\_ppp\_set\_serial\_read} -\subsubsection*{Description} -This function will associate the read function from an external source (e.g. a UART device API) -to the read functionality of the PPP driver. Setting up a proper read/write interface is necessary -for the PPP driver to work properly. - -The function associated with the read must be non-blocking, no matter the execution model of the system. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_set\_serial\_read(struct pico\_device *dev, int (*sread)(struct pico\_device *, void *, int))} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\item \texttt{sread} - a pointer to a function of type \texttt{int fn(struct pico\_device *, void *, int)} - specifying the target serial read function. The function prototype will be called with the device pointer, - a buffer to be filled with serial data, and the maximum lenght of the usable buffer. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the serial read function is successfully associated. - -\subsubsection*{Example} -\begin{verbatim} - -static int my_serial_read(struct pico_device *dev, void *buf, int len) -{ - return nonblock_uart_read(buf, len); -} - -pico_ppp_set_serial_read(ppp, my_serial_read); -\end{verbatim} - -\subsection{pico\_ppp\_set\_serial\_write} -\subsubsection*{Description} -This function will associate the write function from an external source (e.g. a UART device API) -to the write functionality of the PPP driver. Setting up a proper read/write interface is necessary -for the PPP driver to work properly. - -The function associated with the write must be non-blocking, no matter the execution model of the system. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_set\_serial\_write(struct pico\_device *dev, int (*swrite)(struct pico\_device *, const void *, int))} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\item \texttt{swrite} - a pointer to a function of type \texttt{int fn(struct pico\_device *, const void *, int)} - specifying the target serial write function. The function prototype will be called with the device pointer, - a buffer to be filled with serial data, and the maximum lenght of the usable buffer. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the serial write function is successfully associated. - -\subsubsection*{Example} -\begin{verbatim} - -static int my_serial_write(struct pico_device *dev, const void *buf, int len) -{ - return nonblock_uart_write(buf, len); -} - -pico_ppp_set_serial_write(ppp, my_serial_write); -\end{verbatim} - -\subsection{pico\_ppp\_set\_serial\_set\_speed} -\subsubsection*{Description} -This function will associate the set\_speed function from an external source (e.g. a UART device API) -to dynamically set the UART speed for the interface with the PPP driver. - -Calling this function is not mandatory for the PPP UART interface to work. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_set\_serial\_set\_speed(struct pico\_device *dev, int (*sset\_speed)(struct pico\_device *, uint32\_t))} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\item \texttt{sset\_speed} - a pointer to a function of type \texttt{int fn(struct pico\_device *, uint32\_t speed)} - specifying the target serial set\_speed function. The function prototype will be called with the device pointer and - the speed at which the UART should be configured by PPP. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the serial set\_speed function is successfully associated. - -\subsubsection*{Example} -\begin{verbatim} - -static int my_serial_set_speed(struct pico_device *dev, uint32_t speed) -{ - return uart_set_speed(speed); -} - -pico_ppp_set_serial_set_speed(ppp, my_serial_set_speed); -\end{verbatim} - - -\subsection{pico\_ppp\_set\_apn} -\subsubsection*{Description} -This function allows the configuration of the APN name in order for PPP to correctly establish the connection -to the remote Access Point gateway. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_set\_apn(struct pico\_device *dev, const char *apn);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\item \texttt{apn} - a string containing the Access Point Name. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the APN is correctly configured. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_ppp_set_apn(dev, "internet.apn.name"); - -\end{verbatim} -\subsection{pico\_ppp\_set\_username} -\subsubsection*{Description} -This function will set an username for the PAP/CHAP authentication mechanism. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_set\_username(struct pico\_device *dev, const char *username); } - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\item \texttt{username} - a string specifying the desired username. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the username is successfully configured. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_ppp_set_username(dev, "john"); - -\end{verbatim} -\subsection{pico\_ppp\_set\_password} -\subsubsection*{Description} -This function will set the password for the PAP/CHAP authentication mechanism. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_set\_password(struct pico\_device *dev, const char *password); } - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\item \texttt{username} - a string specifying the desired password. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the password is successfully configured. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_ppp_set_password(dev, "secret"); -\end{verbatim} - -\subsection{pico\_ppp\_connect} -\subsubsection*{Description} -This function will enable the PPP connection, by triggering the startup of the handshakes -required at all levels. If the connection is dropped, the system will try to reconnect by restarting -the handshakes, until \texttt{pico\_ppp\_disconnect} is finally called. - - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_connect(struct pico\_device *ppp)} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the device is successfully connecting. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_ppp_connect(dev); - -\end{verbatim} -\subsection{pico\_ppp\_disconnect} -\subsubsection*{Description} -This function will disable the PPP connection, by triggering a disconnection, and by disabling the -reconnect feature, if enabled. - -\subsubsection*{Function prototype} -\texttt{int pico\_ppp\_disconnect(struct pico\_device *ppp)} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the device is successfully put in disconnected state. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_ppp_disconnect(dev); - -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_api_slaacv4.tex b/ext/picotcp/docs/user_manual/chap_api_slaacv4.tex deleted file mode 100644 index 5833a6b..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_slaacv4.tex +++ /dev/null @@ -1,44 +0,0 @@ -\section{SLAACV4 Module} - -% Short description/overview of module functions - - -\subsection{pico\_slaacv4\_claimip} - -\subsubsection*{Description} -This function starts the ip claiming process for a device. It will generate first the local link ip using -as seed the mac address of the device. Then it will start the claim procedure described in RFC3927. -In case of success the IP is registered to the IP layer and returned using the callback function. -In case of error, code SLAACV4\_ERROR is returned. Errors occur when the maximum number of conflicts is reached. -Use the IP returned only if the return code is SLAACV4\_SUCCESS. - -\subsubsection*{Function prototype} -\texttt{pico\_slaacv4\_claimip(struct pico\_device *dev, void (*cb)(struct pico\_ip4 *ip, uint8\_t code));} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} -\item \texttt{*cb} - a callback function returning the ip claimed and a return code (SLAACV4\_ERROR | SLAACV4\_SUCCESS) -\end{itemize} - -\subsubsection*{Return value} -0 returned if the claiming has started successfully - -\subsubsection*{Example} -\begin{verbatim} - -dev = pico_get_device(sdev); - -ret = pico_slaacv4_claimip(dev, slaacv4_cb); - -\end{verbatim} - -\subsection{pico\_slaacv4\_unregisterip} - -\subsubsection*{Description} -This function allows to unregister the local link ip in usage. The function will remove from the route table -the local link ip and will reset the internal state of the SLAACV4 module - -\subsubsection*{Function prototype} -\texttt{void pico\_slaacv4\_unregisterip(void);} - diff --git a/ext/picotcp/docs/user_manual/chap_api_sntp_c.tex b/ext/picotcp/docs/user_manual/chap_api_sntp_c.tex deleted file mode 100644 index 29e31f8..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_sntp_c.tex +++ /dev/null @@ -1,96 +0,0 @@ -\section{SNTP client} - -% Short description/overview of module functions -This module allows you to sync your device to to a specified (s)ntp server. -You can then retreive the time with the pico$\_$sntp$\_$gettimeofday function. - - -\subsection{pico$\_$sntp$\_$sync} - -\subsubsection*{Description} -Function to sync the local time to a given sntp server in string notation. DNS resolution will be done automatically. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_sntp_sync(char *sntp_server, void (*cb_synced)(pico_err_t status)); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{sntp$\_$server} - String with the sntp server to get the time from -\item \texttt{cb$\_$synced} - Callback function that is called when the synchronisation process is done. The status variable indicates wheter the synchronisation was successful or not. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the synchronisation operation has successfully started. When both IPv4 and IPv6 are enabled, success on one is sufficient. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EPROTONOSUPPORT} - compiled without DNS support -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_sntp_sync("ntp.nasa.gov", &callback); -\end{verbatim} - - -\subsection{pico$\_$sntp$\_$sync$\_$ip} - -\subsubsection*{Description} -Function to sync the local time to a given sntp server in IP address notation. -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_sntp_sync_ip(union pico_address *sntp_addr, void (*cb_synced)(pico_err_t status)); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{sntp$\_$addr} - IP address of the sntp server to get the time from -\item \texttt{cb$\_$synced} - Callback function that is called when the synchronisation process is done. The status variable indicates wheter the synchronisation was successful or not. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the synchronisation operation has successfully started. When both IPv4 and IPv6 are enabled, success on one is sufficient. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_sntp_sync_ip(&sntp_addr, &callback); -\end{verbatim} - - -\subsection{pico$\_$sntp$\_$gettimeofday} - -\subsubsection*{Description} -Function to get the current time. Be sure to call the pico$\_$sntp$\_$sync function to synchronise BEFORE calling this function. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_sntp_gettimeofday(struct pico_timeval *tv); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{tv} - Pointer to a time$\_$val struct in which the current time will be set. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 if the time is set. -On error, -1 is returned and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Example} -\begin{verbatim} -int ret = pico_sntp_gettimeofday(tv); -\end{verbatim} - - - diff --git a/ext/picotcp/docs/user_manual/chap_api_sock.tex b/ext/picotcp/docs/user_manual/chap_api_sock.tex deleted file mode 100644 index 7ca4f4c..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_sock.tex +++ /dev/null @@ -1,800 +0,0 @@ -\section{Socket calls} - -% Short description/overview of module functions -With the socket calls, the user can open, close, bind, \ldots sockets and do read -or write operations. The provided transport protocols are UDP and TCP. - -\subsection{pico$\_$socket$\_$open} - -\subsubsection*{Description} -This function will be called to open a socket from the application level. The created -socket will be unbound and not connected. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, -void (*wakeup)(uint16_t ev, struct pico_socket *s)); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{net} - Network protocol, \texttt{PICO$\_$PROTO$\_$IPV4} = 0, \texttt{PICO$\_$PROTO$\_$IPV6} = 41 -\item \texttt{proto} - Transport protocol, \texttt{PICO$\_$PROTO$\_$TCP} = 6, \texttt{PICO$\_$PROTO$\_$UDP} = 17 -\item \texttt{wakeup} - Callback function that accepts 2 parameters: -\begin{itemize}[noitemsep] -\item \texttt{ev} - Events that apply to that specific socket, see further -\item \texttt{s} - Pointer to a socket of type struct \texttt{pico$\_$socket} -\end{itemize} -\end{itemize} - -\subsubsection*{Possible events for sockets} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$SOCK$\_$EV$\_$RD} - triggered when new data arrives on the socket. A new receive action can be taken by the socket owner because this event indicates there is new data to receive. -\item \texttt{PICO$\_$SOCK$\_$EV$\_$WR} - triggered when ready to write to the socket. Issuing a write/send call will now succeed if the buffer has enough space to allocate new outstanding data. -\item \texttt{PICO$\_$SOCK$\_$EV$\_$CONN} - triggered when connection is established (TCP only). This event is received either after a successful call to \texttt{pico$\_$socket$\_$connect} to indicate that the connection has been established, or on a listening socket, indicating that a call to \texttt{pico$\_$socket$\_$accept} may now be issued in order to accept the incoming connection from a remote host. -\item \texttt{PICO$\_$SOCK$\_$EV$\_$CLOSE} - triggered when a FIN segment is received (TCP only). This event indicates that the other endpont has closed the connection, so the local TCP layer is only allowed to send new data until a local shutdown or close is initiated. PicoTCP is able to keep the connection half-open (only for sending) after the FIN packet has been received, allowing new data to be sent in the TCP CLOSE$\_$WAIT state. -\item \texttt{PICO$\_$SOCK$\_$EV$\_$FIN} - triggered when the socket is closed. No further communication is possible from this point on the socket. -\item \texttt{PICO$\_$SOCK$\_$EV$\_$ERR} - triggered when an error occurs. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns a pointer to the declared socket (\texttt{struct pico$\_$socket *}). -On error the socket is not created, \texttt{NULL} is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EPROTONOSUPPORT} - protocol not supported -\item \texttt{PICO$\_$ERR$\_$ENETUNREACH} - network unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -sk_tcp = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &wakeup); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$read} - -\subsubsection*{Description} -This function will be called to read data from a connected socket. The function checks that the socket is bound and connected before attempting to receive data. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_read(struct pico_socket *s, void *buf, int len); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer where the received data will be stored -\item \texttt{len} - Length of the buffer (in bytes), represents the maximum amount of bytes that can be read -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes read. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EIO} - input/output error -\item \texttt{PICO$\_$ERR$\_$ESHUTDOWN} - cannot read after transport endpoint shutdown -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -bytesRead = pico_socket_read(sk_tcp, buffer, bufferLength); -\end{verbatim} - - - -\subsection{pico$\_$socket$\_$write} - -\subsubsection*{Description} -This function will be called to write the content of a buffer to a socket that has been previously connected. -This function checks that the socket is bound, connected and that it is allowed to send data, i.e. there hasn't been a local shutdown. -This is the preferred function to use when writing data from the application to a connected stream. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_write(struct pico_socket *s, void *buf, int len); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of a (constant) buffer where the data is stored -\item \texttt{len} - Length of the data buffer \texttt{buf} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes written to the socket. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EIO} - input/output error -\item \texttt{PICO$\_$ERR$\_$ENOTCONN} - the socket is not connected -\item \texttt{PICO$\_$ERR$\_$ESHUTDOWN} - cannot send after transport endpoint shutdown -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -bytesWritten = pico_socket_write(sk_tcp, buffer, bufLength); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$sendto} - -\subsubsection*{Description} -This function sends data from the local address to the remote address, without checking -whether the remote endpoint is connected. Specifying the destination is particularly useful while sending single datagrams -to different destinations upon consecutive calls. This is the preferred mechanism to send datagrams to a remote destination -using a UDP socket. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_sendto(struct pico_socket *s, const void *buf, int len, -void *dst, uint16_t remote_port); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Length of the buffer \texttt{buf} -\item \texttt{dst} - Pointer to the origin of the IPv4/IPv6 frame header -\item \texttt{remote$\_$port} - Portnumber of the receiving socket -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes written to the socket. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -bytesWritten = pico_socket_sendto(sk_tcp, buf, len, &sk_tcp->remote_addr, -sk_tcp->remote_port); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$recvfrom} - -\subsubsection*{Description} -This function is called to receive data from the specified socket. -It is useful when called in the context of a non-connected socket, to receive -the information regarding the origin of the data, namely the origin address and -the remote port number. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, -void *orig, uint16_t *remote_port); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Maximum allowed length for the data to be stored in the buffer \texttt{buf} -\item \texttt{orig} - Pointer to the origin of the IPv4/IPv6 frame, (peer IP address), can be NULL -\item \texttt{remote$\_$port} - Pointer to the port number of the sender socket, can be NULL -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes read from the socket. On success, if \texttt{orig} -is not NULL, The address of the remote endpoint is stored in the memory area pointed by \texttt{orig}. -In the same way, \texttt{remote$\_$port} will contain the portnumber of the sending socket, unless a NULL is passed -from the caller. - -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ESHUTDOWN} - cannot read after transport endpoint shutdown -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -bytesRcvd = pico_socket_recvfrom(sk_tcp, buf, bufLen, &peer, &port); -\end{verbatim} - -\subsection{Extended Socket operations} -The interface provided by sendto/recvfrom can be extended to include more information about the network communication. -This is especially useful in UDP communication, and whenever extended information is needed about the single datagram and its encapsulation in the networking layer. - -PicoTCP offers an extra structure that can be used to set and retrieve message information while transmitting and receiving datagrams, respectively. The structure \texttt{pico$\_$msginfo} is defined as follows: -\begin{verbatim} -struct pico_msginfo { - struct pico_device *dev; - uint8_t ttl; - uint8_t tos; -}; -\end{verbatim} - - - -\subsection{pico$\_$socket$\_$sendto$\_$extended} - -\subsubsection*{Description} -This function is an extension of the \texttt{pico$\_$socket$\_$sendto} function described above. It's exactly the same but it adds up an additional argument to set TTL and QOS information on the outgoing packet which contains the datagram. - -The usage of the extended argument makes sense in UDP context only, as the information is set at packet level, and only with UDP there is a 1:1 correspondence between datagrams and IP packets. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_sendto_extended(struct pico_socket *s, const void *buf, int len, -void *dst, uint16_t remote_port, struct pico_msginfo *info); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Length of the data that is stored in the buffer (in bytes) -\item \texttt{dst} - IPv4 or IPv6 address of the destination peer where th frame is sent -\item \texttt{remote$\_$port} - Port number of the receiving socket at the remote endpoint -\item \texttt{info} - Extended information about the packet containing this datagram. Only the fields "ttl" and "tos" are taken into consideeration, while "dev" is ignored. - -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes written to the socket. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_msginfo info = { }; -info.ttl = 5; -bytesWritten = pico_socket_sendto_extended(sk_tcp, buf, len, &sk_tcp->remote_addr, -sk_tcp->remote_port, &info); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$recvfrom$\_$extended} - -\subsubsection*{Description} -This function is an extension to the normal \texttt{pico$\_$socket$\_$recvfrom} function, which allows to retrieve additional information about the networking layer that has been involved in the delivery of the datagram. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, -void *orig, uint16_t *remote_port, struct pico_msginfo *info); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Maximum allowed length for the data to be stored in the buffer \texttt{buf} -\item \texttt{orig} - Pointer to the origin of the IPv4/IPv6 frame header, can be NULL -\item \texttt{remote$\_$port} - Pointer to the port number of the sender socket, can be NULL -\item \texttt{info} - Extended information about the incoming packet containing this datagram. The device where the packet was received is pointed by info->dev, the maximum TTL for the packet is stored in info->ttl, and finally the field info->tos keeps track of the flags in IP header's QoS. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes read from the socket. On success, if \texttt{orig} -is not NULL, The address of the remote endpoint is stored in the memory area pointed by \texttt{orig}. -In the same way, \texttt{remote$\_$port} will contain the portnumber of the sending socket, unless a NULL is passed -from the caller. - -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ESHUTDOWN} - cannot read after transport endpoint shutdown -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_msginfo info; -bytesRcvd = pico_socket_recvfrom_extended(sk_tcp, buf, bufLen, &peer, &port, &info); -if (info && info->dev) { - printf("Socket received a datagram via device %s, ttl:%d, tos: %08x\n", - info->dev->name, info->ttl, info->tos); -} -\end{verbatim} - - -\subsection{pico$\_$socket$\_$send} - -\subsubsection*{Description} -This function is called to send data to the specified socket. -It checks if the socket is connected and then calls the -\texttt{pico$\_$socket$\_$sendto} function. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_send(struct pico_socket *s, const void *buf, int len); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Length of the buffer \texttt{buf} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes written to -the socket. On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOTCONN} - the socket is not connected -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -bytesRcvd = pico_socket_send(sk_tcp, buf, bufLen); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$recv} - -\subsubsection*{Description} -This function directly calls the \texttt{pico$\_$socket$\_$recvfrom} function. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_recv(struct pico_socket *s, void *buf, int len); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Maximum allowed length for the data to be stored in the buffer \texttt{buf} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes read -from the socket. On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ESHUTDOWN} - cannot read after transport endpoint shutdown -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -bytesRcvd = pico_socket_recv(sk_tcp, buf, bufLen); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$bind} - -\subsubsection*{Description} -This function binds a local IP-address and port to the specified socket. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{local$\_$addr} - Void pointer to the local IP-address -\item \texttt{port} - Local portnumber to bind with the socket -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull bind. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$ENXIO} - no such device or address -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_bind(sk_tcp, &sockaddr4->addr, &sockaddr4->port); -\end{verbatim} - -\subsection{pico$\_$socket$\_$getname} - -\subsubsection*{Description} -This function returns the local IP-address and port previously bound to the specified socket. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, - uint16_t *proto); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{local$\_$addr} - Address (IPv4 or IPv6) previously associated to this socket -\item \texttt{port} - Local portnumber associated to the socket -\item \texttt{proto} - Proto of the address returned in the \texttt{local$\_$addr} field. Can be either \texttt{PICO$\_$PROTO$\_$IPV4} or \texttt{PICO$\_$PROTO$\_$IPV6} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 and populates the three fields {local$\_$addr} \texttt{port} and \texttt{proto} accordingly. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument(s) provided -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_getname(sk_tcp, address, &port, &proto); -if (errMsg == 0) { - if (proto == PICO_PROTO_IPV4) - addr4 = (struct pico_ip4 *)address; - else - addr6 = (struct pico_ip6 *)address; -} -\end{verbatim} - -\subsection{pico$\_$socket$\_$getpeername} - -\subsubsection*{Description} -This function returns the IP-address of the remote peer connected to the specified socket. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, - uint16_t *proto); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{remote$\_$addr} - Address (IPv4 or IPv6) associated to the socket remote endpoint -\item \texttt{port} - Local portnumber associated to the socket -\item \texttt{proto} - Proto of the address returned in the \texttt{local$\_$addr} field. Can be either \texttt{PICO$\_$PROTO$\_$IPV4} or \texttt{PICO$\_$PROTO$\_$IPV6} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 and populates the three fields {local$\_$addr} \texttt{port} and \texttt{proto} accordingly. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument(s) provided -\item \texttt{PICO$\_$ERR$\_$ENOTCONN} - the socket is not connected to any peer -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_getpeername(sk_tcp, address, &port, &proto); -if (errMsg == 0) { - if (proto == PICO_PROTO_IPV4) - addr4 = (struct pico_ip4 *)address; - else - addr6 = (struct pico_ip6 *)address; -} -\end{verbatim} - - -\subsection{pico$\_$socket$\_$connect} - -\subsubsection*{Description} -This function connects a local socket to a remote socket of a server that is listening, or permanently associate a remote UDP peer as default receiver for any further outgoing traffic through this socket. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_connect(struct pico_socket *s, void *srv_addr, -uint16_t remote_port); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{srv$\_$addr} - Void pointer to the remote IP-address to connect to -\item \texttt{remote$\_$port} - Remote port number on which the socket will be connected to -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull connect. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EPROTONOSUPPORT} - protocol not supported -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_connect(sk_tcp, &sockaddr4->addr, sockaddr4->port); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$listen} - -\subsubsection*{Description} -A server can use this function when a socket is opened and bound to start listening to it. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_listen(struct pico_socket *s, int backlog); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{backlog} - Maximum connection requests -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull listen start. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EISCONN} - socket is connected -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_listen(sk_tcp, 3); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$accept} - -\subsubsection*{Description} -When a server is listening on a socket and the client is trying to connect. -The server on its side will wakeup and acknowledge the connection by calling the this function. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, -uint16_t *local_port); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{orig} - Pointer to the origin of the IPv4/IPv6 frame header -\item \texttt{local$\_$port} - Portnumber of the local socket (pointer) -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns the pointer to a \texttt{struct pico$\_$socket} that -represents the client thas was just connected. Also \texttt{orig} will contain the requesting -IP-address and \texttt{remote$\_$port} will contain the portnumber of the requesting socket. -On error, \texttt{NULL} is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -client = pico_socket_accept(sk_tcp, &peer, &port); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$shutdown} - -\subsubsection*{Description} -Used by the \texttt{pico$\_$socket$\_$close} function to shutdown read and write mode for -the specified socket. With this function one can close a socket for reading -and/or writing. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_shutdown(struct pico_socket *s, int mode); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{mode} - \texttt{PICO$\_$SHUT$\_$RDWR}, \texttt{PICO$\_$SHUT$\_$WR}, \texttt{PICO$\_$SHUT$\_$RD} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull socket shutdown. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_shutdown(s, PICO_SHUT_RDWR); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$close} - -\subsubsection*{Description} -Function used on application level to close a socket. Always closes read and write connection. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_close(struct pico_socket *s); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull socket shutdown. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_close(sk_tcp); -\end{verbatim} - - - -\subsection{pico$\_$socket$\_$setoption} -\label{socket:setoption} -\subsubsection*{Description} -Function used to set socket options. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_setoption(struct pico_socket *s, int option, void *value); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{option} - Option to be set (see further for all options) -\item \texttt{value} - Value of option (void pointer) -\end{itemize} - -\subsubsection*{Available socket options} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$TCP$\_$NODELAY} - Disables/enables the Nagle algorithm (TCP Only). -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$KEEPCNT} - Set number of probes for TCP keepalive -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$KEEPIDLE} - Set timeout value for TCP keepalive probes (in ms) -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$KEEPINTVL} - Set interval between TCP keepalive retries in case of no reply (in ms) -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$LINGER} - Set linger time for TCP TIME$\_$WAIT state (in ms) -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$RCVBUF} - Set receive buffer size for the socket -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$RCVBUF} - Set receive buffer size for the socket -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$RCVBUF} - Set receive buffer size for the socket -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$SNDBUF} - Set send buffer size for the socket -\item \texttt{PICO$\_$IP$\_$MULTICAST$\_$IF} - (Not supported) Set link multicast datagrams are sent from, default is first added link -\item \texttt{PICO$\_$IP$\_$MULTICAST$\_$TTL} - Set TTL (0-255) of multicast datagrams, default is 1 -\item \texttt{PICO$\_$IP$\_$MULTICAST$\_$LOOP} - Specifies if a copy of an outgoing multicast datagram is looped back as long as it is a member of the multicast group, default is enabled -\item \texttt{PICO$\_$IP$\_$ADD$\_$MEMBERSHIP} - Join the multicast group specified in the \textit{pico\_ip\_mreq} structure passed in the value argument -\item \texttt{PICO$\_$IP$\_$DROP$\_$MEMBERSHIP} - Leave the multicast group specified in the \textit{pico\_ip\_mreq} structure passed in the value argument -\item \texttt{PICO$\_$IP$\_$ADD$\_$SOURCE$\_$MEMBERSHIP} - Join the source-specific multicast group specified in the \textit{pico\_ip\_mreq\_source} structure passed in the value argument -\item \texttt{PICO$\_$IP$\_$DROP$\_$SOURCE$\_$MEMBERSHIP} - Leave the source-specific multicast group specified in the \textit{pico\_ip\_mreq\_source} structure passed in the value argument -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull setting of socket option. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_socket_setoption(sk_tcp, PICO_TCP_NODELAY, NULL); - -uint8_t ttl = 2; -ret = pico_socket_setoption(sk_udp, PICO_IP_MULTICAST_TTL, &ttl); - -uint8_t loop = 0; -ret = pico_socket_setoption(sk_udp, PICO_IP_MULTICAST_LOOP, &loop); - -struct pico_ip4 inaddr_dst, inaddr_link; -struct pico_ip_mreq mreq = {{0},{0}}; -pico_string_to_ipv4("224.7.7.7", &inaddr_dst.addr); -pico_string_to_ipv4("192.168.0.2", &inaddr_link.addr); -mreq.mcast_group_addr = inaddr_dst; -mreq.mcast_link_addr = inaddr_link; -ret = pico_socket_setoption(sk_udp, PICO_IP_ADD_MEMBERSHIP, &mreq); -ret = pico_socket_setoption(sk_udp, PICO_IP_DROP_MEMBERSHIP, &mreq) -\end{verbatim} - - -\subsection{pico$\_$socket$\_$getoption} - -\subsubsection*{Description} -Function used to get socket options. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_getoption(struct pico_socket *s, int option, void *value); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{option} - Option to be set (see further for all options) -\item \texttt{value} - Value of option (void pointer) -\end{itemize} - -\subsubsection*{Available socket options} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$TCP$\_$NODELAY} - Nagle algorithm, \texttt{value} casted to \texttt{(int *)} (0 = disabled, 1 = enabled) -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$RCVBUF} - Read current receive buffer size for the socket -\item \texttt{PICO$\_$SOCKET$\_$OPT$\_$SNDBUF} - Read current receive buffer size for the socket -\item \texttt{PICO$\_$IP$\_$MULTICAST$\_$IF} - (Not supported) Link multicast datagrams are sent from -\item \texttt{PICO$\_$IP$\_$MULTICAST$\_$TTL} - TTL (0-255) of multicast datagrams -\item \texttt{PICO$\_$IP$\_$MULTICAST$\_$LOOP} - Loop back a copy of an outgoing multicast datagram, as long as it is a member of the multicast group, or not. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 after a succesfull getting of socket option. The value of -the option is written to \texttt{value}. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -ret = pico_socket_getoption(sk_tcp, PICO_TCP_NODELAY, &stat); - -uint8_t ttl = 0; -ret = pico_socket_getoption(sk_udp, PICO_IP_MULTICAST_TTL, &ttl); - -uint8_t loop = 0; -ret = pico_socket_getoption(sk_udp, PICO_IP_MULTICAST_LOOP, &loop); -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_api_tftp.tex b/ext/picotcp/docs/user_manual/chap_api_tftp.tex deleted file mode 100644 index ab4df9b..0000000 --- a/ext/picotcp/docs/user_manual/chap_api_tftp.tex +++ /dev/null @@ -1,911 +0,0 @@ -\section{TFTP} - -% Short description/overview of module functions -This module provides support for Trivial File Transfer Protocol (TFTP). -The support includes client and server implementation, both of them can be active at the same time. - -Flows must be split up into TFTP blocks on the sender side, and reassembled from block len -on the receiving side. Please note that a block whose size is less than the block size indicates -the end of the transfer. - -To indicate the end of a transfer where the content is aligned with the block size, an additional -transmission of zero bytes must follow the flow. - -Function pico$\_$tftp$\_$listen must be used to start the server with a proper callback that should be provided by the user. To reject a request received by the server the server callback must call pico$\_$tftp$\_$reject$\_$request. - -In order to start transmission or reception of files a session handler must be obtained with a call to pico$\_$tftp$\_$session$\_$setup. The created session may take advantage of the Extenxed Options of the TFTP protocol invoking pico$\_$tftp$\_$set$\_$option before starting using it. - -Real file transaction is started using the functions pico$\_$tftp$\_$start$\_$tx and pico$\_$tftp$\_$start$\_$rx; both require a callback that must be provided by the user to handle single chunks of the transmission. The transmitter callback must use pico$\_$tftp$\_$send function to send each block of data. - -In case of problem the session can be aborted (and an error message is sent to the remote side) using pico$\_$tftp$\_$abort. - -When a transfer is complete the session became invalid and must not be used any more. - -\subsection*{Application driven interface} - -In some use case is preferable to have an application driven behaviour. The API provide 5 specific functions to use TFTP in this scenario. - -The way to obtain a session handler suited for this purpose is an invocation to the function pico$\_$tftp$\_$app$\_$setup. The synchro variable passed to this function will play a key role during the management of the transfer. - -As usual the section can be instructed to use Extended Options using pico$\_$tftp$\_$set$\_$option before starting the file transfer. - -Once the session is created, the application can start receiving a file with a call to the function pico$\_$tftp$\_$app$\_$start$\_$rx or, if needs to transmit, invoking pico$\_$tftp$\_$app$\_$start$\_$tx. - -After the file transfer is started the user is allowed to perform data handling only when the synchro variable associated with the session is not 0. It is set to 0 after calling pico$\_$tftp$\_$app$\_$setup. A value that differ to 0 means that a single chunk is ready to be handled. - -Single chunk of data are received using pico$\_$tftp$\_$get and transmitted with the use of the function pico$\_$tftp$\_$put. - -Once the file transfer ends, both for completion or in case of error, the session is no more valid. - - -\subsection{pico\_tftp\_listen} - -\subsubsection*{Description} -Start up a TFTP server listening for GET/PUT requests on the given port. -The function pointer passed as callback in the \texttt{cb} argument will be invoked upon a new -transfer request received from the network, and the call will pass the information about: -\begin{itemize}[noitemsep] -\item The address of the remote peer asking for a transfer -\item The remote port of the peer -\item The type of transfer requested, via the \texttt{opcode} parameter being either \texttt{PICO$\_$TFTP$\_$RRQ} or \texttt{PICO$\_$TFTP$\_$WRQ}, for get or put requests respectively. -\end{itemize} - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_tftp_listen(uint16_t family, void (*cb)(union pico_address *addr, - uint16_t port, uint16_t opcode, char *filename, int32_t len)); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{family} - The chosen socket family. Accepted values are \texttt{PICO$\_$PROTO$\_$IPV4} for IPv4 and \texttt{PICO$\_$PROTO$\_$IPV6} for IPv6. -\item \texttt{cb} - a pointer to the callback function, defined by the user, that will be called upon a new transfer request. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsubsection*{Example} -\begin{verbatim} -/* Example of a TFTP listening service callback */ - -void tftp_listen_cb(union pico_address *addr, uint16_t port, - uint16_t opcode, char *filename, int32_t len) -{ - struct note_t *note; - struct pico_tftp_session *session; - - printf("TFTP listen callback (BASIC) from remote port %" PRIu16 ".\n", - short_be(port)); - if (opcode == PICO_TFTP_RRQ) { - printf("Received TFTP get request for %s\n", filename); - note = transfer_prepare(&session, 't', filename, addr, family); - start_tx(session, filename, port, cb_tftp_tx, note); - } else if (opcode == PICO_TFTP_WRQ) { - printf("Received TFTP put request for %s\n", filename); - note = transfer_prepare(&session, 'r', filename, addr, family); - start_rx(session, filename, port, cb_tftp_rx, note); - } -} - -// Code fragment to demostrate the use of pico_tftp_listen: -if (!is_server_enabled) { - pico_tftp_listen(PICO_PROTO_IPV4, (commands->operation == 'S') ? - tftp_listen_cb_opt : tftp_listen_cb); - is_server_enabled = 1; -} -\end{verbatim} - - -\subsection{pico\_tftp\_reject\_request} - -\subsection*{Description} -This message is used in listen callback to reject a request with an error message. -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_reject_request(union pico_address *addr, uint16_t port, - uint16_t error_code, const char *error_message); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{addr} - The address of the remote peer; it must match the address where the request came from. -\item \texttt{port} - The port on the remote peer; it must match the address where the request came from. -\item \texttt{error$\_$code} - Error reason, possible values are: - -\begin{tabular}{ll} -TFTP$\_$ERR$\_$UNDEF & Not defined, see error message (if any) \\ -TFTP$\_$ERR$\_$ENOENT & File not found \\ -TFTP$\_$ERR$\_$EACC & Access violation \\ -TFTP$\_$ERR$\_$EXCEEDED & Disk full or allocation exceeded \\ -TFTP$\_$ERR$\_$EILL & Illegal TFTP operation \\ -TFTP$\_$ERR$\_$ETID & Unknown transfer ID \\ -TFTP$\_$ERR$\_$EEXIST & File already exists \\ -TFTP$\_$ERR$\_$EUSR & No such user \\ -TFTP$\_$ERR$\_$EOPT & Option negotiation \\ -\end{tabular} -\item \texttt{message} - Text message to attach. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, - uint16_t opcode, char *filename, int32_t len) -{ - struct note_t *note; - struct pico_tftp_session *session; - int options; - uint8_t timeout; - int32_t filesize; - int ret; - - printf("TFTP listen callback (OPTIONS) from remote port %" PRIu16 ".\n", - short_be(port)); - /* declare the options we want to support */ - ret = pico_tftp_parse_request_args(filename, len, &options, - &timeout, &filesize); - if (ret) - pico_tftp_reject_request(addr, port, TFTP_ERR_EOPT, - "Malformed request"); - - if (opcode == PICO_TFTP_RRQ) { - printf("Received TFTP get request for %s\n", filename); - note = transfer_prepare(&session, 'T', filename, addr, family); - - if (options & PICO_TFTP_OPTION_TIME) - pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - if (options & PICO_TFTP_OPTION_FILE) { - ret = get_filesize(filename); - if (ret < 0) { - pico_tftp_reject_request(addr, port, TFTP_ERR_ENOENT, - "File not found"); - return; - } - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); - } - - start_tx(session, filename, port, cb_tftp_tx_opt, note); - } else { /* opcode == PICO_TFTP_WRQ */ - printf("Received TFTP put request for %s\n", filename); - - note = transfer_prepare(&session, 'R', filename, addr, family); - if (options & PICO_TFTP_OPTION_TIME) - pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - if (options & PICO_TFTP_OPTION_FILE) - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); - - start_rx(session, filename, port, cb_tftp_rx_opt, note); - } -} -\end{verbatim} - - -\subsection{pico\_tftp\_session\_setup} - -\subsubsection*{Description} -Obtain a session handler to use for the next file transfer with a remote location. - -\subsubsection*{Function prototype} -\begin{verbatim} -struct pico_tftp_session * pico_tftp_session_setup(union pico_address *a, - uint16_t family); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{a} - The address of the peer to be contacted. In case of a solicited transfer, it must match the address where the request came from. -\item \texttt{family} - The chosen socket family. Accepted values are \texttt{PICO$\_$PROTO$\_$IPV4} for IPv4 and \texttt{PICO$\_$PROTO$\_$IPV6} for IPv6. -\end{itemize} - -\subsubsection*{Return value} -In case of success a session handler is returned. In case of failure, NULL is returned and pico$\_$err is set accordingly. - -\subsubsection*{Example} -\begin{verbatim} -struct pico_tftp_session * make_session_or_die(union pico_address *addr, - uint16_t family) -{ - struct pico_tftp_session * session; - - session = pico_tftp_session_setup(addr, family); - if (!session) { - fprintf(stderr, "TFTP: Error in session setup\n"); - exit(3); - } - return session; -} -\end{verbatim} - - -\subsection{pico\_tftp\_set\_option} - -\subsection*{Description} -This function is used to require the use of Extended Options for TFTP transfer associate to a session according to RFC 2347 and RFC 2349. It should be used before the invocation of pico$\_$tftp$\_$start$\_$rx or pico$\_$tftp$\_$start$\_$tx unless the setting is related to the timeout. -In order to require Transfer size Option PICO$\_$TFTP$\_$OPTION$\_$FILE must be used and its value set to the file size in case of a Write Request or to 0 in case of a Read Request. -To require to adopt a specific fixed value for the timeout PICO$\_$TFTP$\_$OPTION$\_$TIME must be used with a value ranging between 1 and 255. If this option is set to a value of 0 (or not used at all) an adaptive timeout algorithm will take care of the retransmissions. - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_set_option(struct pico_tftp_session *session, - uint8_t type, int32_t value); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Section handler to use for the file transfer. -\item \texttt{type} - Option to set; accepted values are PICO$\_$TFTP$\_$OPTION$\_$FILE for Transfer size Option or PICO$\_$TFTP$\_$OPTION$\_$TIME for Timeout interval Option. -\item \texttt{value} - Option value to send. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -filesize = get_filesize(commands->filename); -if (filesize < 0) { - fprintf(stderr, "TFTP: unable to read size of file %s\n", - commands->filename); - exit(3); -} -pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); -start_tx(session, commands->filename, short_be(PICO_TFTP_PORT), - cb_tftp_tx_opt, note); -\end{verbatim} - - -\subsection{pico\_tftp\_get\_option} - -\subsection*{Description} -This function is used to retrieve the values of Extended Options that has been set to a session according to RFC 2347 and RFC 2349. -In order to ask Transfer size Option value PICO$\_$TFTP$\_$OPTION$\_$FILE must be used; it may be used for example for example in receiver callback for calculation of remaining bytes to be received to complete the current transfer. -To query the timeout PICO$\_$TFTP$\_$OPTION$\_$TIME must be used; a value ranging between 1 and 255 will be returned in the value parameter if the fixed interval is in place. If the call return -1 and pico$\_$err is set to PICO$\_$ERR$\_$ENOENT the adaptive timeout algorithm is running. - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_set_option(struct pico_tftp_session *session, - uint8_t type, int32_t *value); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Section handler to use for the file transfer. -\item \texttt{type} - Option to query; accepted values are PICO$\_$TFTP$\_$OPTION$\_$FILE for Transfer size Option or PICO$\_$TFTP$\_$OPTION$\_$TIME for Timeout interval Option. -\item \texttt{value} - Pointer to an integer variable where to store the value. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -int cb_tftp_tx_opt(struct pico_tftp_session *session, uint16_t event, - uint8_t *block, int32_t len, void *arg) -{ - int ret; - int32_t filesize; - - if (event == PICO_TFTP_EV_OPT) { - ret = pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, &filesize); - if (ret) - printf("TFTP: Option filesize is not used\n"); - else - printf("TFTP: We expect to transmit %" PRId32 " bytes\n", - filesize); - event = PICO_TFTP_EV_OK; - } - - return cb_tftp_tx(session, event, block, len, arg); -} -\end{verbatim} - - -\subsection{pico\_tftp\_parse\_request\_args} - -\subsection*{Description} -This function is used to extract Extension Options eventually present in Read or Write request (in the listen callback) or in Option ACKnowledge messages (in transmitter or receiver callback when event is equal to PICO$\_$TFTP$\_$EV$\_$OPT). -Note that timeout and filesize are modified only if the corresponding option is found in the received message. - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_parse_request_args(char *args, int32_t len, int *options, - uint8_t *timeout, int32_t *filesize); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{args} - Pointer to the buffer containing the arguments: filename for listen callback and block for rx or tx callback. -\item \texttt{len} - Length of the buffer containing the arguments; same value of the len parameter in callbacks. -\item \texttt{options} - Pointer to the variable that will contain the set of options found. Presence of single options can be then verified anding it with PICO$\_$TFTP$\_$OPTION$\_$FILE or PICO$\_$TFTP$\_$OPTION$\_$TIME. -\item \texttt{timeout} - Pointer to the variable that will contain the timeout value (if present in the options). -\item \texttt{filesize} - Pointer to the variable that will contain the filesize value (if present in the options).. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, - uint16_t opcode, char *filename, int32_t len) -{ - struct note_t *note; - struct pico_tftp_session *session; - int options; - uint8_t timeout; - int32_t filesize; - int ret; - - printf("TFTP listen callback (OPTIONS) from remote port %" PRIu16 ".\n", - short_be(port)); - /* declare the options we want to support */ - ret = pico_tftp_parse_request_args(filename, len, &options, - &timeout, &filesize); - if (ret) - pico_tftp_reject_request(addr, port, TFTP_ERR_EOPT, - "Malformed request"); - - if (opcode == PICO_TFTP_RRQ) { - printf("Received TFTP get request for %s\n", filename); - note = transfer_prepare(&session, 'T', filename, addr, family); - - if (options & PICO_TFTP_OPTION_TIME) - pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - if (options & PICO_TFTP_OPTION_FILE) { - ret = get_filesize(filename); - if (ret < 0) { - pico_tftp_reject_request(addr, port, TFTP_ERR_ENOENT, - "File not found"); - return; - } - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); - } - - start_tx(session, filename, port, cb_tftp_tx_opt, note); - } else { /* opcode == PICO_TFTP_WRQ */ - printf("Received TFTP put request for %s\n", filename); - - note = transfer_prepare(&session, 'R', filename, addr, family); - if (options & PICO_TFTP_OPTION_TIME) - pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - if (options & PICO_TFTP_OPTION_FILE) - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); - - start_rx(session, filename, port, cb_tftp_rx_opt, note); - } -} -\end{verbatim} - - -\subsection{pico\_tftp\_start\_tx} - -\subsubsection*{Description} -Start a TFTP transfer. The action can be unsolicited (client PUT operation) or solicited (server responding to a GET request). -In either case, the transfer will happen one block at a time, and the callback provided by the user will be called to notify the acknowledgement for the successful of each transfer, transfer of the last block, reception of an option acknowledge message (client mode) or whenever an error occurs. Any error during the TFTP transfer will cancel the transfer itself. -The possible values for the \texttt{event} variable in callback are: -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$TFTP$\_$EV$\_$OK} Time to send another chunk of data. -\item \texttt{PICO$\_$TFTP$\_$EV$\_$OPT} Option acknowledge has been received. -\item \texttt{PICO$\_$TFTP$\_$EV$\_$ERR$\_$PEER} An error has occurred remotely. -\item \texttt{PICO$\_$TFTP$\_$EV$\_$ERR$\_$LOCAL} An internal error has occurred. -\end{itemize} - -\subsubsection*{Function prototype} -\begin{verbatim} -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); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Session handler to use for the file transfer. -\item \texttt{port} - The port on the remote peer. -\item \texttt{filename} - The name of the file to be transferred. In case of solicited transfer, it must match the filename provided during the request. -\item \texttt{user$\_$cb} - The callback provided by the user to be called upon each block transfer, option acknowledge or in case of error. -\item \texttt{arg} - The pointer is sent as argument to the callback. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsubsection*{Example} -\begin{verbatim} -void start_tx(struct pico_tftp_session *session, - const char *filename, uint16_t port, - int (*tx_callback)(struct pico_tftp_session *session, uint16_t err, - uint8_t *block, int32_t len, void *arg), - struct note_t *note) -{ - if (pico_tftp_start_tx(session, port, filename, tx_callback, note)) { - fprintf(stderr, "TFTP: Error in initialization\n"); - exit(1); - } -} -\end{verbatim} - - -\subsection{pico\_tftp\_send} -\subsubsection*{Description} -Send the next block during an active TFTP transfer. This is ideally called every time the user callback is triggered by the protocol, indicating that the transfer of the last block has been acknowledged. The user should not call this function unless it's solicited by the protocol during an active transmit session. - -\subsubsection*{Function prototype} -\begin{verbatim} -int32_t pico_tftp_send(struct pico_tftp_session *session, - const uint8_t *data, int32_t len); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - the session handler to use for the file transfer. -\item \texttt{data} - the content of the block to be transferred. -\item \texttt{len} - the size of the buffer being transmitted. If $<$ \texttt{BLOCKSIZE}, the transfer is concluded. In order to terminate a transfer where the content is aligned to \texttt{BLOCKSIZE}, a zero-sized \texttt{pico$\_$tftp$\_$send} must be called at the end of the transfer. -\end{itemize} - -\subsubsection*{Return value} -In case of success, the number of bytes transmitted is returned. In case of failure, -1 is returned and pico$\_$err is set accordingly. - -\subsubsection*{Example} -\begin{verbatim} -int cb_tftp_tx(struct pico_tftp_session *session, uint16_t event, - uint8_t *block, int32_t len, void *arg) -{ - struct note_t *note = (struct note_t *) arg; - - if (event != PICO_TFTP_EV_OK) { - fprintf(stderr, "TFTP: Error %" PRIu16 ": %s\n", event, block); - exit(1); - } - - len = read(note->fd, tftp_txbuf, PICO_TFTP_PAYLOAD_SIZE); - - if (len >= 0) { - note->filesize += len; - pico_tftp_send(session, tftp_txbuf, len); - if (len < PICO_TFTP_PAYLOAD_SIZE) { - printf("TFTP: file %s (%" PRId32 - " bytes) TX transfer complete!\n", - note->filename, note->filesize); - close(note->fd); - del_note(note); - } - } else { - perror("read"); - fprintf(stderr, - "Filesystem error reading file %s," - " cancelling current transfer\n", note->filename); - pico_tftp_abort(session, TFTP_ERR_EACC, "Error on read"); - del_note(note); - } - - if (!clipboard) - pico_timer_add(3000, deferred_exit, NULL); - - return len; -} -\end{verbatim} - - -\subsection{pico\_tftp\_start\_rx} - -\subsubsection*{Description} -Start a TFTP transfer. The action can be unsolicited (client GET operation) or solicited (server responding to a PUT request). -In either case, the transfer will happen one block at a time, and the callback provided by the user will be called upon successful transfer of a block, whose content can be directly accessed via the \texttt{block} field, reception of an option acknowledge messagge (client mode) or whenever an error occurs. -The possible values for the \texttt{event} variable in callback are: -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$TFTP$\_$EV$\_$OK} Previously sent block has been acknowledge. -\item \texttt{PICO$\_$TFTP$\_$EV$\_$OPT} Option acknowledge has been received. -\item \texttt{PICO$\_$TFTP$\_$EV$\_$ERR$\_$PEER} An error has occurrend remotely. -\item \texttt{PICO$\_$TFTP$\_$EV$\_$ERR$\_$LOCAL} An internal error has occurred. -\end{itemize} - -\subsubsection*{Function prototype} -\begin{verbatim} -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); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - the session handler to use for the file transfer. -\item \texttt{port} - The port on the remote peer. -\item \texttt{filename} - The name of the file to be transfered. In case of solicited transfer, it must match the filename provided during the request. -\item \texttt{user$\_$cb} - The callback provided by the user to be called upon each block transfer, option acknowledge or in case of error. This is the callback where the incoming data is processed. When len is less than the block size, the transfer is over. -\item \texttt{arg} - The pointer sent as argument to the callback. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsubsection*{Example} -\begin{verbatim} -void start_rx(struct pico_tftp_session *session, - const char *filename, uint16_t port, - int (*rx_callback)(struct pico_tftp_session *session, uint16_t err, - uint8_t *block, int32_t len, void *arg), - struct note_t *note) -{ - if (pico_tftp_start_rx(session, port, filename, rx_callback, note)) { - fprintf(stderr, "TFTP: Error in initialization\n"); - exit(1); - } -} -\end{verbatim} - - -\subsection{pico\_tftp\_get\_file\_size} - -\subsection*{Description} -This function is used to retrieve the file size (if transmitted by the remote or set as session option). It is equivalent to a call to pico$\_$tftp$\_$get$\_$option(session, PICO$\_$TFTP$\_$OPTION$\_$FILE, $\&$file$\_$size); - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_get_file_size(struct pico_tftp_session *session, - int32_t *file_size); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Section handler to use for the file transfer. -\item \texttt{file$\_$size} - Pointer to an integer variable where to store the value. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -ret = pico_tftp_get_file_size(session, &file_size); -if (ret) - printf("Information about file size has not been received"\n); -\end{verbatim} - - -\subsection{pico\_tftp\_abort} -\subsubsection*{Description} -When called this function aborts associated ongoing transmission and notifying the other endpoint with a proper error message. After a call to this function the session is closed automatically. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_tftp_abort(struct pico_tftp_session *session, - uint16_t error, const char *reason); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - the session handler related to the session to abort. -\item \texttt{error} - Error reason code, possible values are: - -\begin{tabular}{ll} -TFTP$\_$ERR$\_$UNDEF & Not defined, see error message (if any) \\ -TFTP$\_$ERR$\_$ENOENT & File not found \\ -TFTP$\_$ERR$\_$EACC & Access violation \\ -TFTP$\_$ERR$\_$EXCEEDED & Disk full or allocation exceeded \\ -TFTP$\_$ERR$\_$EILL & Illegal TFTP operation \\ -TFTP$\_$ERR$\_$ETID & Unknown transfer ID \\ -TFTP$\_$ERR$\_$EEXIST & File already exists \\ -TFTP$\_$ERR$\_$EUSR & No such user \\ -TFTP$\_$ERR$\_$EOPT & Option negotiation \\ -\end{tabular} -\item \texttt{reason} - Text message to attach. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -int cb_tftp_rx(struct pico_tftp_session *session, uint16_t event, - uint8_t *block, int32_t len, void *arg) -{ - struct note_t *note = (struct note_t *) arg; - int ret; - - if (event != PICO_TFTP_EV_OK) { - fprintf(stderr, "TFTP: Error %" PRIu16 ": %s\n", event, block); - exit(1); - } - - note->filesize += len; - if (write(note->fd, block, len) < 0) { - perror("write"); - fprintf(stderr, "Filesystem error writing file %s," - " cancelling current transfer\n", note->filename); - pico_tftp_abort(session, TFTP_ERR_EACC, "Error on write"); - del_note(note); - } else { - if (len != PICO_TFTP_PAYLOAD_SIZE) { - printf("TFTP: file %s (%" PRId32 - " bytes) RX transfer complete!\n", - note->filename, note->filesize); - close(note->fd); - del_note(note); - } - } - - if (!clipboard) - pico_timer_add(3000, deferred_exit, NULL); - - return len; -} -\end{verbatim} - - -\subsection{pico\_tftp\_close\_server} - -\subsection*{Description} -This function is used to shutdown the TFTP server. - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_close_server(void); -\end{verbatim} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -ret = pico_tftp_close_server(); -if (ret) - printf(stderr, "Failure shutting down the server\n"); -\end{verbatim} - - -\subsection{pico\_tftp\_app\_setup} - -\subsection*{Description} -Obtain a session handler to use for the next file transfer with a remote location in application driven mode. - -\subsection*{Function prototype} -\begin{verbatim} -struct pico_tftp_session * pico_tftp_app_setup(union pico_address *a, - uint16_t port, uint16_t family, int *synchro); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{a} - The address of the peer to be contacted. In case of a solicited transfer, it must match the address where the request came from. -\item \texttt{port} - The port on the remote peer. -\item \texttt{family} - The chosen socket family. Accepted values are \texttt{PICO$\_$PROTO$\_$IPV4} for IPv4 and \texttt{PICO$\_$PROTO$\_$IPV6} for IPv6. -\item \texttt{synchro} - Variable to handle the synchronization. -\end{itemize} - -\subsubsection*{Return value} -In case of success a session handler is returned. In case of failure, NULL is returned and pico$\_$err is set accordingly. - -\subsection*{Example} -\begin{verbatim} -session = pico_tftp_app_setup(&server_address, short_be(PICO_TFTP_PORT), - PICO_PROTO_IPV4, &synchro); -if (!session) { - fprintf(stderr, "Error in pico_tftp_app_setup\n"); - exit(1); -} -\end{verbatim} - - -\subsection{pico\_tftp\_app\_start\_rx} - -\subsection*{Description} -Application driven function used to request to read a remote file. The transfer will happen one block at a time using pico$\_$tftp$\_$app$\_$get. - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_app_start_rx(struct pico_tftp_session *session, - const char *filename); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Session handler to use for the file transfer. -\item \texttt{filename} - The name of the file to be received. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -printf("Start receiving file %s with options set to %d\n", filename, options); - -if (options) { - ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0); - if (ret) { - fprintf(stderr, "Error in pico_tftp_set_option\n"); - exit(1); - } -} - -ret = pico_tftp_app_start_rx(session, filename); -if (ret) { - fprintf(stderr, "Error in pico_tftp_app_start_rx\n"); - exit(1); -} -\end{verbatim} - - -\subsection{pico\_tftp\_app\_start\_tx} - -\subsection*{Description} -Application driven function used to request to write a remote file. The transfer will happen one block at a time using pico$\_$tftp$\_$app$\_$put. - -\subsection*{Function prototype} -\begin{verbatim} -int pico_tftp_app_start_tx(struct pico_tftp_session *session, - const char *filename); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Session handler to use for the file transfer. -\item \texttt{filename} - The name of the file to be sent. -\end{itemize} - -\subsubsection*{Return value} -This function returns 0 if succeeds or -1 in case of errors (pico$\_$err is set accordingly). - -\subsection*{Example} -\begin{verbatim} -printf("Start sending file %s with options set to %d\n", filename, options); - -if (options) { - ret = get_filesize(filename); - if (ret < 0) { - fprintf(stderr, "Error in get_filesize\n"); - exit(1); - } - - ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); - if (ret) { - fprintf(stderr, "Error in pico_tftp_set_option\n"); - exit(1); - } -} - -ret = pico_tftp_app_start_tx(session, filename); -if (ret) { - fprintf(stderr, "Error in pico_tftp_app_start_rx\n"); - exit(1); -} -\end{verbatim} - - -\subsection{pico\_tftp\_get} - -\subsection*{Description} -Read the next block during an active TFTP transfer. The len field must always be equal to PICO$\_$TFTP$\_$PAYLOAD$\_$SIZE. Once the file has been sent or after an error the session is no more valid. - -\subsection*{Function prototype} -\begin{verbatim} -int32_t pico_tftp_get(struct pico_tftp_session *session, - uint8_t *data, int32_t len); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Session handler to use for the file transfer. -\item \texttt{data} - Buffer where to store the acquired payload. -\item \texttt{len} - Length of the buffer size to receive; it is equal to the fixed chunk size. -\end{itemize} - -\subsubsection*{Return value} -This function returns the number of received bytes of payload (0 included) if succeeds. In case of error a negative number is returned. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{-1} At least one of the passed arguments are invalid. -\item \texttt{-PICO$\_$TFTP$\_$EV$\_$ERR$\_$PEER} Remote failure. -\item \texttt{-PICO$\_$TFTP$\_$EV$\_$ERR$\_$LOCAL} Local failure. -\end{itemize} - -\subsection*{Example} -\begin{verbatim} -for(;left; left -= countdown) { - usleep(2000); //PICO_IDLE(); - pico_stack_tick(); - if (countdown) - continue; - - if (*synchro) { - len = pico_tftp_get(session, buf, PICO_TFTP_PAYLOAD_SIZE); - if (len < 0) { - fprintf(stderr, "Failure in pico_tftp_get\n"); - close(fd); - countdown = 1; - continue; - } - ret = write(fd, buf, len); - if (ret < 0) { - fprintf(stderr, "Error in write\n"); - pico_tftp_abort(session, TFTP_ERR_EXCEEDED, "File write error"); - close(fd); - countdown = 1; - continue; - } - printf("Written %" PRId32 " bytes to file (synchro=%d)\n", - len, *synchro); - - if (len != PICO_TFTP_PAYLOAD_SIZE) { - close(fd); - printf("Transfer complete!\n"); - countdown = 1; - } - } -} -\end{verbatim} - - -\subsection{pico\_tftp\_put} - -\subsection*{Description} -Send the next block during an active TFTP transfer. The len field, with the exception of last invocation must always be equal to PICO$\_$TFTP$\_$PAYLOAD$\_$SIZE. Once the file has been sent or after an error the session is no more valid. - -\subsection*{Function prototype} -\begin{verbatim} -int32_t pico_tftp_put(struct pico_tftp_session *session, - uint8_t *data, int32_t len); -\end{verbatim} - -\subsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{session} - Session handler to use for the file transfer. -\item \texttt{data} - Pointer to the data to be transmitted. -\item \texttt{len} - Length of the buffer size to transmit; last chunk must be $<$ of the maximum buffer size (0 if file size was a multiple of maximum buffer size). - -\end{itemize} - -\subsubsection*{Return value} -This function returns the number of transmitted payload data (len) if succeeds. In case of error a negative number is returned. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{-1} At least one of the passed arguments are invalid. -\item \texttt{-PICO$\_$TFTP$\_$EV$\_$ERR$\_$PEER} Remote failure. -\item \texttt{-PICO$\_$TFTP$\_$EV$\_$ERR$\_$LOCAL} Local failure. -\end{itemize} - -\subsection*{Example} -\begin{verbatim} -for(;left; left -= countdown) { - usleep(2000); //PICO_IDLE(); - pico_stack_tick(); - if (countdown) - continue; - - if (*synchro) { - ret = read(fd, buf, PICO_TFTP_PAYLOAD_SIZE); - if (ret < 0) { - fprintf(stderr, "Error in read\n"); - pico_tftp_abort(session, TFTP_ERR_EACC, "File read error"); - close(fd); - countdown = 1; - continue; - } - printf("Read %" PRId32 " bytes from file (synchro=%d)\n", - len, *synchro); - - len = pico_tftp_put(session, buf, ret); - if (len < 0) { - fprintf(stderr, "Failure in pico_tftp_put\n"); - close(fd); - countdown = 1; - continue; - } - - if (len != PICO_TFTP_PAYLOAD_SIZE) { - close(fd); - printf("Transfer complete!\n"); - countdown = 1; - } - } -} -\end{verbatim} diff --git a/ext/picotcp/docs/user_manual/chap_license.tex b/ext/picotcp/docs/user_manual/chap_license.tex deleted file mode 100644 index a248315..0000000 --- a/ext/picotcp/docs/user_manual/chap_license.tex +++ /dev/null @@ -1,11 +0,0 @@ -Unless you have received a written document by PicoTCP copyright holders stating otherwise, -the software described in this document is distributed under the terms of the GNU General -Public License version 2 only. - -The terms of the license are reported below. - -\begin{center} -{\bf\large GNU General Public license} -{\bf Version 2, June 1991} -\end{center} -\input {gpl-2.0} diff --git a/ext/picotcp/docs/user_manual/chap_overview.tex b/ext/picotcp/docs/user_manual/chap_overview.tex deleted file mode 100644 index f7409ac..0000000 --- a/ext/picotcp/docs/user_manual/chap_overview.tex +++ /dev/null @@ -1,68 +0,0 @@ -PicoTCP is a complete TCP/IP stack, intended for embedded devices and -designed to run on different architectures and networking -hardware. The architecture of the stack allows easy selection of the features -needed for any particular use, taking into account the sizing and -the performance of the platform on which the code is to run. -Even if it is designed -to allow for size and performance constraints, the chosen approach is to -comply with the latest standards in the telecommunications research, including -the latest proposals, in order to achieve the highest standards for -today's inter-networking communications. PicoTCP is distributed as -a library to be integrated with application and form a combination for -any hardware-specific firmware. - - -The main characteristics of the library are the following: -\begin{itemize} -\item \textbf{Modularity} Each component of the stack is deployed in a -separate module, allowing the selection at compile time of the components needed to -be included for any specific platform, depending on the particular use case. -We know that saving memory and resources is often mission-critical for a -project, and therefore PicoTCP is fully focussed on saving -up to the last byte of memory. -\item \textbf{Code Quality} Every component added to the -stack must pass a complete set of validation tests. Before new code can be -introduced it is scanned and proof-checked by three separate levels of -quality enforcement. The process related to the validation of the code is -one of the major tasks of the engineering team. In the top-down approach of the design, a -new module has to pass the review of our senior architects, to have it comply -with the general guidelines. The development of the smaller -components is done in a test-driven way, providing a specific unit test for each function call. -Finally, functional non-regression tests are performed -after the feature development is complete, and all the tests are automatically -scheduled to run several times per day to check for functional regressions. -\item \textbf{Adherence to the standards} The protocols -included in the stack are done following stepare designed by following meticulously the guidelines -provided by the International Engineering Task Force (IETF) with regards to -inter-networking communication. A strong adherence to the standards guarantees a -smooth integration with all the existing TCP/IP stacks, when communicating -with both other embedded devices and with the PC/server world. -\item \textbf{Features} A fully-featured protocol implementation including all those non-mandatory -features means better data-transfer performances, coverage of rare/unique -network scenarios and topologies and a better integration with all types of -networking hardware devices. -\item \textbf{Transparency} The availability of the source code to the Free -Software community is an important added value of PicoTCP. -%Our programmers -%are proud of the aestethic of their code, and they show it with no -%hesitation to the attention of the rest of the world. -The constant peer reviews and constructive comments on the -design and the development choices that PicoTCP receives from the academic world -and from several hundreds of hobbyists and professionals who read the code, -are an essential element in the quality build-up of the product. -%PicoTCP constantly receives peer-reviews and constructive comments on the -%design and the development choices from the academic world and from several -%hundreds of hobbists and professionals who read the code. -%We strongly -%believe that software is not about keeping things secret: whenever one is -%convinced by the quality of their work, there is absolutely nothing to hide. -\item \textbf{Simplicity} The APIs provided to access the library -facilities, both from the applications as well as from the device drivers, are -small and well documented. This concurs with the goal of the library to facilitate -the integration with the surroundings and minimize the time used to combine -the stack with existing code. The support required to port to a new -architecture is so small it is reduced to a set of macros defined in a -header file specific for the platform. -\end{itemize} - - diff --git a/ext/picotcp/docs/user_manual/chap_rfcs.tex b/ext/picotcp/docs/user_manual/chap_rfcs.tex deleted file mode 100644 index c5ef6be..0000000 --- a/ext/picotcp/docs/user_manual/chap_rfcs.tex +++ /dev/null @@ -1,187 +0,0 @@ - -\begin{longtable}{ | l | p{15cm} | } -\hline -{\bf RFC} & -{\bf Description} \\ \hline - -RFC 768 & -User Datagram Protocol (UDP) \\ \hline - -RFC 791 & -Internet Protocol (IP) \\ \hline - -RFC 792 & -Internet Control Message Protocol (ICMP) \\ \hline - -RFC 793 & -Transmission Control Protocol (TCP) \\ \hline - -RFC 816 & -Fault Isolation and Recovery \\ \hline - -RFC 826 & -Address Resolution Protocol (ARP) \\ \hline - -RFC 879 & -The TCP Maximum Segment Size and Related Topics \\ \hline - -RFC 894 & -IP over Ethernet \\ \hline - -RFC 896 & -Congestion Control in IP/TCP Internetworks \\ \hline - -RFC 919 & -Broadcasting Internet Datagrams \\ \hline - -RFC 922 & -Broadcasting Internet Datagrams in the Presence of Subnets \\ \hline - -RFC 950 & -Internet Standard Subnetting Procedure \\ \hline - -RFC 1009 & -Requirements for Internet Gateways \\ \hline - -RFC 1034 & -Domain NamesConcepts and Facilities \\ \hline - -RFC 1035 & -Domain NamesImplementation and Specification \\ \hline - -RFC 1071 & -Computing the Internet Checksum \\ \hline - -RFC 1112 & -Internet Group Management Protocol (IGMP) \\ \hline - -RFC 1122 & -Requirements for Internet HostsCommunication Layers \\ \hline - -RFC 1123 & -Requirements for Internet Hosts - Application and Support (\textsuperscript{1}) \\ \hline - -RFC 1191 & -Path MTU Discovery (\textsuperscript{1})\\ \hline - -RFC 1323 & -TCP Extensions for High Performance \\ \hline - -RFC 1332 & -The PPP Internet Protocol Control Protocol (IPCP) \\ \hline - -RFC 1334 & -PPP Authentication Protocols \\ \hline - -RFC 1337 & -TIME-WAIT Assassination Hazards in TCP \\ \hline - -RFC 1350 & -The TFTP Protocol (Revision 2) \\ \hline - -RFC 1534 & -Interoperation Between DHCP and BOOTP \\ \hline - -RFC 1542 & -Clarifications and Extensions for the Bootstrap Protocol \\ \hline - -RFC 1661 & -The Point-to-Point Protocol (PPP) \\ \hline - -RFC 1662 & -PPP in HDLC-like Framing \\ \hline - -RFC 1812 & -Requirements for IP Version 4 Routers \\ \hline - -RFC 1878 & -Variable Length Subnet Table For IPv4 \\ \hline - -RFC 1886 & -DNS Extensions to Support IP Version 6 (\textsuperscript{1}) \\ \hline - -RFC 1994 & -PPP Challenge Handshake Authentication Protocol (CHAP) \\ \hline - -RFC 2018 & -TCP Selective Acknowledgment Options \\ \hline - -RFC 2131 & -Dynamic Host Configuration Protocol (DHCP) \\ \hline - -RFC 2132 & -DHCP Options and BOOTP Vendor Extensions \\ \hline - -RFC 2236 & -Internet Group Management Protocol, Version 2 \\ \hline - -RFC2347 & -TFTP Option Extension \\ \hline - -RFC 2349 & -TFTP Timeout Interval and Transfer Size Options \\ \hline - -RFC 2460 & -Internet Protocol, Version 6 (IPv6) Specification \\ \hline - -RFC 2581 & -TCP Congestion Control \\ \hline - -RFC 2663 & -IP Network Address Translator (NAT) Terminology and Considerations \\ \hline - -RFC 2710 & -Multicast Listener Discovery (MLD) for IPv6 \\ \hline - -RFC 3042 & -Enhancing TCP's Loss Recovery Using Limited Transmit \\ \hline - -RFC 3315 & -Dynamic Host Configuration Protocol for IPv6 (DHCPv6) (\textsuperscript{1}) \\ \hline - -RFC 3376 & -Internet Group Management Protocol, Version 3 \\ \hline - -RFC 3517 & -A Conservative Selective Acknowledgment (SACK)-based Loss Recovery Algorithm for TCP \\ \hline - -RFC 3561 & -Ad-hoc On-Demand Distance Vector (AODV) Routing \\ \hline - -RFC 3626 & -Optimized Link State Routing Protocol (OLSR) \\ \hline - -RFC 3782 & -The NewReno Modification to TCP's Fast Recovery Algorithm \\ \hline - -RFC 3810 & -Multicast Listener Discovery Version 2 (MLDv2) for IPv6 \\ \hline - -RFC 3927 & -Dynamic Configuration of IPv4 Link-Local Addresses \\ \hline - -RFC 4291 & -IP Version 6 Addressing Architecture \\ \hline - -RFC 4443 & -Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification \\ \hline - -RFC 4861 & -Neighbor Discovery for IP version 6 (IPv6) \\ \hline - -RFC 4862 & -IPv6 Stateless Address Autoconfiguration \\ \hline - -RFC 6691 & -TCP Options and Maximum Segment Size (MSS) \\ \hline - -RFC 6762 & -Multicast DNS \\ \hline - -RFC 6763 & -DNS-based Service Discovery \\ \hline - -\end{longtable} - -(\textsuperscript{1}) Work in progress -(\textsuperscript{2}) Experimental diff --git a/ext/picotcp/docs/user_manual/layout.tex b/ext/picotcp/docs/user_manual/layout.tex deleted file mode 100644 index 00ff75f..0000000 --- a/ext/picotcp/docs/user_manual/layout.tex +++ /dev/null @@ -1,71 +0,0 @@ -%Thesistemplate LaTeX De Nayer 2008-2009 -%Stefan Bouwens, Dave Geeradyn & Toon Goedem\'e - -%PACKAGES -%\usepackage{times} -%\usepackage[dvips]{graphicx} -\usepackage{url} -\usepackage[english,dutch]{babel} -\usepackage[T1]{fontenc} -\usepackage[all]{xy} -\usepackage{amssymb} -%\usepackage[breaklinks=true, bookmarksopen=true]{hyperref} -\usepackage[small,bf,hang]{caption} -\renewcommand{\captionfont}{\small\itshape} -\usepackage{natbib} -\bibpunct{(}{)}{;}{a}{,}{,} - -\usepackage{listings} -\lstloadlanguages{[visual]c++} -\lstset{ basicstyle=\small, - basicstyle=\ttfamily, - numbers=left, numberstyle=\tiny, stepnumber=1, numbersep=5pt, - tabsize=3, - keywordstyle=\color{black}\bfseries, - commentstyle=\color{gray}\itshape, - frame=single, - breaklines=true - } - - -%LAYOUT -%\bibliographystyle{agsm} - -\setcounter{secnumdepth}{3} -\setcounter{tocdepth}{3} - -\setlength{\textheight}{237mm} -\setlength{\textwidth}{160mm} -%\setlength{\columnsep}{0.3125in} -\setlength{\topmargin}{-0.54cm} -\setlength{\headheight}{15pt} -%\setlength{\headsep}{0in} -%\setlength{\parindent}{1pc} -\setlength{\oddsidemargin}{0.46cm} % Centers text. -\setlength{\evensidemargin}{-.54cm} -% -%Linkermarge 30 mm, rechtermarge 20 mm, bovenmarge 20 mm, ondermarge 20 mm. -%2,54 - -\usepackage{fancyhdr} -\pagestyle{fancy} -% with this we ensure that the chapter and section -% headings are in lowercase. -\renewcommand{\chaptermark}[1]{% - \markboth{#1}{}} -\renewcommand{\sectionmark}[1]{% - \markright{\thesection\ #1}} -\fancyhf{} % delete current header and footer -\fancyhead[LE,RO]{\bfseries\thepage} -\fancyhead[LO]{\bfseries\rightmark} -\fancyhead[RE]{\bfseries\leftmark} -\renewcommand{\headrulewidth}{0.5pt} -\renewcommand{\footrulewidth}{0pt} -\addtolength{\headheight}{0.5pt} % space for the rule -\fancypagestyle{plain}{% - \fancyhead{} % get rid of headers on plain pages - \renewcommand{\headrulewidth}{0pt} % and the line -} - -\parskip 6pt % sets spacing between paragraphs -\parindent 0pt % sets leading space for paragraphs \ No newline at end of file diff --git a/ext/picotcp/docs/user_manual/layout1.tex b/ext/picotcp/docs/user_manual/layout1.tex deleted file mode 100644 index 946b6ba..0000000 --- a/ext/picotcp/docs/user_manual/layout1.tex +++ /dev/null @@ -1,27 +0,0 @@ -% Altran Intelligent Systems -% -% LAYOUT TEXT -% =========== - -%\documentclass[11pt, a4paper, openright,oneside]{book} -\documentclass[11pt, a4paper,oneside]{report} - -\usepackage[english]{babel} -\usepackage[latin1]{inputenc} -%\usepackage[T1]{fontenc} -\usepackage{graphicx} -\usepackage{natbib} -%\usepackage{hyperref} -\usepackage[hang,flushmargin]{footmisc} - -\usepackage{fullpage} -\parskip 4pt % sets spacing between paragraphs -\parindent 0pt % sets leading space for paragraphs - -\makeatletter -\renewcommand{\@makechapterhead}[1]{% -%\vspace*{50 pt}% -{\setlength{\parindent}{0pt} \raggedright \normalfont -\bfseries\Huge\thechapter.\ #1 -\par\nobreak\vspace{40 pt}}} -\makeatother diff --git a/ext/picotcp/docs/user_manual/template_api.tex b/ext/picotcp/docs/user_manual/template_api.tex deleted file mode 100644 index 140fe35..0000000 --- a/ext/picotcp/docs/user_manual/template_api.tex +++ /dev/null @@ -1,38 +0,0 @@ -\section{MODULE} - -% Short description/overview of module functions - - -\subsection{FUNCTION} - -\subsubsection*{Description} - -\subsubsection*{Function prototype} - -\subsubsection*{Parameters} - -\subsubsection*{Return value} - -\subsubsection*{Errors} - -\subsubsection*{Example} - - -\subsection{FUNCTION} - -\subsubsection*{Description} - -\subsubsection*{Function prototype} - -\subsubsection*{Parameters} - -\subsubsection*{Return value} - -\subsubsection*{Errors} - -\subsubsection*{Example} - - -\subsection{FUNCTION} - -% ... \ No newline at end of file diff --git a/ext/picotcp/docs/user_manual/user_doc.tex b/ext/picotcp/docs/user_manual/user_doc.tex deleted file mode 100644 index 3790ec6..0000000 --- a/ext/picotcp/docs/user_manual/user_doc.tex +++ /dev/null @@ -1,113 +0,0 @@ -% Altran NV -% -% PicoTCP User Documentation main file -% ==================================== - -%\documentclass[11pt, a4paper, openright]{paper} - - -\input{layout1} - -% TEMPS - -%\usepackage{tikz} -%\usepackage[latin1]{inputenc} -%\usepackage{graphicx} -%\usepackage[hang,flushmargin]{footmisc} -%\usepackage{pdfpages} -%\usepackage{tabularx} -%\usepackage{lscape} -%\usepackage{longtable} -%\usepackage{verbatim} -%\usepackage{moreverb} -%\usepackage{listings} -%\usepackage{draftcopy} -%\usepackage{hyperref} -\usepackage{longtable} - -%% to print watermark -% \usepackage{draftwatermark} -% \SetWatermarkText{Altran ISY Confidential} -% \SetWatermarkScale{3} -% \SetWatermarkLightness{0.9} - -% to adjust the space between titles and text -\usepackage[compact]{titlesec} -\titlespacing{\section}{0pt}{*5}{*2} -\titlespacing{\subsection}{0pt}{*4}{*1} -\titlespacing{\subsubsection}{0pt}{*1}{*0} - -% to minimize space between list items -\usepackage{enumitem} - -% To use hyperlinks -\usepackage{hyperref} -% limit toc depth until sections -\setcounter{tocdepth}{1} - - -\begin{document} - -\title{picoTCP User Documentation} -\author{Copyright \copyright 2013-2015 Altran NV. All right reserved.} -\maketitle -\date{\today} -\maketitle - -\thispagestyle{empty} - -Disclaimer -This document is distributed under the terms of Creative Commons CC BY-ND 3.0. -You are free to share unmodified copies of this document, as long as the copyright -statement is kept. Click \href{http://creativecommons.org/licenses/by-nd/3.0/} {here} to view the full license text. - - -\pagenumbering{arabic} - -\selectlanguage{english} - -\tableofcontents - -%\chapter{Introduction} -%\label{chap:intro} -%\input{chap_intro} - -\chapter{Overview} -\label{chap:overview} -\input{chap_overview} - - -\chapter{API Documentation} -\label{chap:api_doc} -The following sections will describe the API for picoTCP. -\input{chap_api_ipv4} -\input{chap_api_ipv6} -\input{chap_api_sock} -\input{chap_api_dhcp_c} -\input{chap_api_dhcp_d} -\input{chap_api_dns_c} -\input{chap_api_mdns} -\input{chap_api_dns_sd} -\input{chap_api_sntp_c} -\input{chap_api_igmp} -\input{chap_api_mld} -\input{chap_api_ipfilter} -\input{chap_api_slaacv4} -\input{chap_api_tftp} -\input{chap_api_ppp} -\input{chap_api_olsr} -\input{chap_api_aodv} - - -\appendix - -% Do not include license -%\chapter{License} -%\label{chap:license} -%\input{chap_license} - -\chapter{Supported RFCs} -\label{chap:rfcs} -\input{chap_rfcs} - -\end{document} diff --git a/ext/picotcp/docs/wiki_images/Protocol input.dia b/ext/picotcp/docs/wiki_images/Protocol input.dia deleted file mode 100644 index 0e49c39f0e77e6deeb395827d847263b1a6d86ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1873 zcmV-X2d?-ZiwFP!000021MOU0lbbdaefO_m$U|Qo83_a^o83&4X{VjprkzRh?2(Pu zrorHXypHqG-`*?Cu9q)=fN`@4%xq?j#XaasI``;aZC=0mvIw+$5hs2WUh5bcx+cPD zTOp;0Uu<71yScMh^|G}3)7AC|GeKf%@+1W}Wz%f>D>4dR#&emNa(a#^_G zvT*Tb;rwL0jA9vcUzQ;!Q4|OsZc$~t63uavDGy+Z?duk9ZvD=eGCJ`7cRWar>A?2( z-T=*PXbZ(_I@bOW`1)X^Tp9g8GQG6 z%h|BCRvRKbS5QGu4-vDK?}_BVG|RWCu{6(`jShLe*zQ=zY;P3;b_x;jjfgYzZ+D?u z%LX`O9F0$b&qUiAZ)OwR|~AU@Mm*b4`v}|NG~_U2Y()v2yef82uNdLMb>iQqCa!G+rjE{ZT4GGr5G+8rt`fUy9^Z~*2C z)(|Kz0};Zk=c~Eed+sRF#So@XHJ8(&=mLdD>364tSVM?HYOm7(zKFaPtd-y2|Mlr( zAI!TC<~AF`WOs=5oken^gGhc%koo{*@A24!NOcQ~zamnRwvoz4m{`mi5)&CVwmJ<~ zrfX0-#40J^SXUTB;4)KW*R&cE@H7g;u?W4iM~(VfZVFS_wTU~#4un@m8q(ZqFq^}97pT=-70Qxd>n{yw!cTTJ;*_? zHN=3~eaJ_Iv^3qFhjtL>@{d~bz$`$6Nof&0e51{QIJ3|zqcnx8?Y_O%%j>`5S)4s< z<)0 zgns*(p4(_GVlB<;4?JJ>F4$$K<5C(FXAQL{h zAWv=k`Q~rV;Jl*}ILOIY6KIDC9D)j^3-=OLGuV58!iMg#5m*3Ay@TWM?kWg(XiE#%NH#a9M`DZL^X8H^4oa=v|b{V<&i zRn&+FFxKi=s-`dFXeyEfXjkufw{zaDn4EoyRWz{?v*{4D2y49C>!eU}TxG%RD+_&Pp=qA$ zp*rB?^IZ5Wd9Lm0q@UICabIpK*vmPC$f8!em3yqtQu`FZNt0X*S%9k2y3hHL(ixn0 zOp*(vhLt-RZg+V~3AxWb(ZmcPnjTBKq=w%K_RH$^MHEKKl21ihw7&z_`Xc^5C3~h) zOk_A#pDQ`{$)va9E6ki4mF>2UQ!Fiu5G8>-jZ+K}?7Bl6sf2(7{7%%2!L+HupNOyH z!y3D~cjbn}LZ*|>VSBG4CpNOEI)umewsN3jX;+)>Ayj}ItErHjk})L>u%~rb|etsyW)rre~P##I65^T%AvG8CFL-DD75?5riFwDX~Ls;4Ro~ zJIqZFl{k)Jcb)dE>t}5mz%0~Y`(xt0O8VwhQvD(3lT)1ZWQDc;oW|~(LGFLmxEcHh LCQ|5neM=M)An@Tk7eK%K`ehae_d3g?G`Z>_0DFN> z#_1$VrdPe&o4@}gd%s>^{4$BcpUvMi3ul43BgyTjtKMBv%zwVTe0X>O@naqqX$InG z0djr$zc7x&OCxmIyS@m5mjz71BDB|5SHq&nqS2zzK@!gNRc{oIKTorCkxY6^sg>L~ zjngc+596!eyHDk-ceyI&vQo~LvghGck1`#8ZY~;{mr`wtp6hJA*x5YIBO_8g&NoCF z%CY}n$gHGtBa}?9-+j8@+tw`9zVuH~ zQKUQS|0#^~eHyU5{B6b^I(w&CG}%6RD-sQ*JVcY?ZurGfcP&eQbX59%lt-gj*VR5s zilY_(c%0(bpH7M3&$o9R4a?FRmxzhfOtZt6i0LAl=zPa8tI9N#bhi?_+|}#ra{G47 z^3vLZU8;z~N1d&T|Lu9H4pt9%g*ZVtE~5LVPcQl;9sNg-i&bNP*TqAceGYyK-pA>} z7V?dV^nz$|)%ychduzRYrZfYD8{IWepU0E}i1rCU405{O51S~`q+~Q&*O8fKgvm74 zHF^eE0nGXm!1h{ax(ItaM*Soj7wt;dv7QabX_jmflH+z>si;J*%?|vAS`Z+pUcNf$ zy3^70u4q<9fr6D+%Z8bCQSWM)ZCCY$Iw-Rcw8%EcM3uWj*iOZ#D313~QDxqTsmSlr zhhYu9-_2VN?yJ0bjP<$#oh)Xn2eW~kwQJ}hYUkl(Ql(0+21B906uXdNO{VFAlmg;Ooc9@!Qb62ITa~x$2@-7-8LMEL%yj)DeV%4$Pc5~q-JwC49ogGo#+=N3$92OJ_5F$>cNGx=*4Cen3b!iI2hCHevg$|-iZLSX^~;@oIr1n~jpfI!On2m>Z) zOS5yFCdp7Ild?grnpq>tfGVri))qFyW;|c7OI`f575HxjW;^92bZNqq)e?pjh6+p7 zauvvnFe`>(mZcBPb}8y!_%PPVbbE_fcO^S}t)&h#vUl|n#vO}x*F(=Lj@3VQx*Je2 z2$*k7f~RkSJA;|4MYl-H=ydS>?NyI%%>9~s(du4Sy_apq=+`QAAgbS3qOiAIzFl+AP6VMV3!DDVqu+gDfyv zyFdS>=PBa}0&A;*N?~QVcz@49Gv>am(w1f7RRFdFNd7~oGi|CkHYoYGD4eB9UGR%_ z21?wK?Cl4V7)Yj+)q|u`HuDHli2BH&Bx>spcnf}-&fT|2F}EZg5(n zYZmh~pNC_;$#&lx1d4R_eRAEW@kj+`p6Q+;(_M21$fGmen=G8`uW3}rbw%eGBsVDK zG6ZSHH&oKnL1lmt0jMDEo2!tWaU`;Rr|rXSnL}=iJ-7AT)^ppp$Zch3ESJDi372Rt zfM7&gV#~21wnza?Ikx3sSoq0##=S!~pdv zKrS)Rsvv+t1AiPS!TRmV?5oGLN<8#Ity4ha#>n(ZP)CJBa$J(ukXwbi?`x;V1}1i| z6NXH3mq=w;n!?y$ zbfT0bRHa<#kd!3Xbgc;t(Gd>$5X`X$QUOLOE>lb?mIG|ikFzp3V}Z#v3T`y8HefE9 zq^5=vBk2=Noh6uhoI1W~h!4RjCs{$e%}Rui;94`&*gywkZi6KhBhoK3XxPBKK_NvS zQ*Z|M<@=RQ8K)0VcIKb*;KG}jr}VmQ4pQ%Qd&^elZ~AMbvnF~)&LASd4P=$RUL_G7 z7=;K)ZV^nPw#My9e;w{7R_jfx3)2GHH@0PUI@Czva%b#zDSITGZI)=gE6E0xhjs+y zhlJ{Czw@N$bxF_B4Xo`rK+gaNq%mG>WRL<$rLnRgpys^<0wU<^0)eTF5s^DYh(&=N zSfKzZQGlNt3jBy$1>3^f+4|+)B(ybwTK8=l@+7IehE!9VvW5Xek`4$0SU_5)Y%=BA zeN@}VO)*m`Xt$0SdV(eK4kYhDdc$05En!w1;y^;Y(fiZ^t)355{8*$}IMsDNq|RFp z>?CFOC=BHiuZSrh;iaAd!S-;{Cb%E^P{35*P#~v<;*%Ck>|u-c z@Dm}e5dV!crOn+$qe)~4L!%)(9Sz}2scYGvmDLovHM01 zV^rA0b*vN_5CO1|#2!6@5OVF)s&8by9J0nMKf8ob;uAu>pRBE)?3=GkHD-i%@O3SZ zwEnC8k+-OLtV1z%1inRD&)R*tmUVI2vl9kH0VbJ^^UE{dQr@Z0_S#f#h-u}(Y2xy9 zYaoB*t>35Q?=Q%@Kd|K#bp45yi0|)6YxMd@T5nB+!JRi>5nP56kmDE(28=^q#*8_| z18d?zB`m+j=G|d3Ol|vW#EAVhh~>|NZk5Bg97{d~o{h?84$Lwl|Ol z#tu)KCWz57+z+d@O}b_8>dnko4Gb+mm($_;V)?=RO|x)zeer)edE}*%ivR$g&k5-O diff --git a/ext/picotcp/docs/wiki_images/Protocol_input.png b/ext/picotcp/docs/wiki_images/Protocol_input.png deleted file mode 100644 index 746cb64614198d7ccd6bc05c2b34a423569726c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25462 zcmb?@by!th^XLIoKvKF91?dK9P(m7{yQNE78l_u6x?8%tTe|a*(%oHm@qX|3yU%m) z{qt_l!+{-Z&6=KBGdu9Jj3~-Wf|n2o1Vvm-SRMj_{Q`l&3?aaRGj&8i9>CWNeMwPa z$m7#bT2pQm1o9dpF8opPThiWwlcs{oBm9va=AYMl^snE%eq9_?5ma$dUsJ7azA*J; z%1oocvS@C_plVzlYUb}yX=NjeMalW$88*zUtG`d-?d{w9Y&P-%a*owgkMr}!_TIs! zrK_KAoR=wf3?k!fFktq5RViHXWwg~DO8D{PM=TL$tpKanbTE()m&!%z=hvI5iG#h8 zeHM#|5U;v?r~vCji4{D&|BoNA46*(8WTAp`C|P9f7?9Q(_A4bTAE|^ED zT(f&aON&5k|NczbYL)r4Uy;5wp)^t3FQZ}Wtr>Cd8JB8aJzb)AUTD^a= z-jBuqjE83lA!D`U94GWyE{eiEBFy1p2e^atgxcIoP~v@v8idv z^^k88DKjHuD49n^UY^BnV?ZwR6EVNr)!FvAh=_@)@)H|vZSBPOmI*aY-J#LpVA1T&RVOF5q@<*iMqFH6`8ApQ3+x+P4-XGjkI!LY zVHN#HYGtdO)Gya_>}BvFtt_Su897tMHxa{|u`w|x-*^QBROysI3GzXqGcy6gZ3PfAMq#W-3m zTXj*-*aJ8tYP6l&9Hn{QBB%3vO^uV8S^mj!h4HZBJ}*g0eZBfMCnKZm;7iAKzv|a7tavG9P0jhZ*y*XbOjl>;yocxV^6~)JggPnRv2OwI z4h#;&v&J&&q$EEb#Q6AmW`|Qn(8q^Mf%MODF)`I&R|J)A|8@m$4yUI6`b8cghJk^R zBb&O|xKAifg*69-B0c*7t}&{XrsW+LGmEA&8+;NL7FPb}5EkwX!DroB$}K1`2NSz9 zPJhF|hajgF76OS~vYaj^P91i#wI$%Nn!i5X+?`GNiQ}$I=;n-ciFTuK*{?NOTpfS% zU6oF|(j+1(DypI37FWkD-Aqpy$=Z3 zy2AJG-vR%dL8IQu@R;v>X_(swQ;xp}Q--VvzlWTfBzT-{jcyDk0!<;4#QE`oXHYUb zZ+s|$d$!ool@IgKOg0X#6rB?Vsg*Y0DQR{cO>+5UzJT`jzeL#2=G&B`{cH^NW!~U4;oSc}L7zUl@ z#)o^8M8~O#UdPZ`N-tlQd3+tnRS6OaA95XkW-Jx7-|K1!*+02%fcXrQX5Vs_*S@8@4;TyZ8lkFII^N+qg z&9$_p7m)*+*4N+PKRCEQ(Yl#BLTtyHl0MP9;8-T+{`PXI#yZt3F(d?;k+J0DmPFc0b)1#Chzvi-nOn2ZpX9;G(xG zzqb~Rl)un@Ni=ldetdJ;3@KsGseErVvnPem6_DvGH+ zk%a~)f$O!X0+kYO9v;v0NtL&vVHVdd&=%3@m1f8XPcxk_`qdarB4AJ@>27Ih=^_A^ z`d7}wrpv`pLJr08_ym`<($dlne>7Yi9IJ(T2Y{J#l`%ztCQPH1 zHq#aB7V({U&4PrG2Dj@I6>aD2wu_j7wn;}y$)F5?lL{a?X#7`R9V={yA6ShBzMXAF zDAG{)Y4F9oWNmgtKRsnOqH&ZgDbYURgl_6CZ#3p93EsUrj+lVK{N@y`Ic!XKnXzjQP>NxA6?BOVYh2%FaSpF_D&b@Y#lX`*g!^=3doK;b_}Kmfwz z>rbK95>OwmP|Vdc9t~7H!*&IO_}vLuRqjxZqKWsfiVol`L#sTo0)>%q=squw*#c3X znwmmU7O9kNENF@sBUi7shzEMa-@gYK6vbR^_WuiSx;L-9vID}yNd-LIyeSQsXjaj+4aXV4)^!FKHOacKmj&}?YVTVfNBG7QM8>i@cJ|#1C_^<34%+XG1+-|c<{NL zZOvBXwzNF@p%BI~pjC>aS10<8j zVMkH6a6-F^nS*0`d^`$WUQ26#XD7d&I><&)6&CX0^!WO2Y)pPKnK7DH&;+Uq#pvnw z%q9ZH4U%>ZTnDAhZlH&{Etqe-OP@i!HWIn)a?JFtzI-7cU*AG%$7mJAzovM@gbmcp z@#W>=M4p1G>P)F#M;wEwPRKnQGh}PNH;NLthe;6;qd;#031z3E3fK;6b;Em{?Ac%* zc6ttRxPQ1k1a^#;nwrb)s?^Lu+12$HJf@+h26QSdFK^Q9%QoaVb5(U_EeHhf&w78X z=k+>nRd-O(OGASa?I!e?G+F}6_5}NYgw0e4shAy5ey+R5M1a#;{>{Z@vDPLN z7;>MVdL4eroHnrHh$F9kD7?B55fHYfOGwGS06pgD=qMEnrwfZ71Bnq!|BODbj-NJq zBnML}oPW+0&+x334M-B*E0-9E^pEhDUKE1E7-`~9HzV*#j&QIh#s>U*_AH;J;pC*g zUrHri5-3qgpA?EMw4yY$7DrAiW1=Fa)FBFfn*ThO8po(V#*l@0>N{Ig5nn7~{LgrL zh%S+Yv98x0{e3;XqLKJTBC-FR&(-@#nkBg1rh?i>@i-4**#3-BalVEA-@*K&tW)Sb zGz)La)=b6aBflMmtU7UZW|5@*b@fhRoxUJPwPn2SRd}s#1Wme6jg=w zLKGUtuooj!AaYwztCiBc%-iFcjh>D6V-(-~2MJqhKTt)i1BOC+C+>)(Bf}GfHZcJ5 z14k;JY4wKmHr5}T@e#)L{O{2*|FRsXtDsST3390xZ%HaXMlLe_s0yq4=8WzmWd@FD zbaw1yOQ>M}H-hsCrt>Ydf0toW2jCQ#zbs|eNN9^!1yp*%wEA!I?6rwFe*@TqXaVDnV3{j+^)P>wW`wgI}#*3*lnDta-vjtZzH4 z-i8A`5^fwUZ4MHMYtxJo2krEa5!X)~tkSL06$HI|p4IG31)-NuI?;+eobIyOpN^QP zYGGmrE7Aixy5C+C)aq*ei-UChgM&tmcm*zfXuwEsy5pi_zN1{=?>7Y*7cp4DJ7u+^ zv1(dj16+}|+#<7a_Ee@bF?uhGRGt3iI1|623U2>Fv;t@fVQhip%PH#CUUgkd`qC79 zcGivHILTcG>a3vhv+}zux9}m77c?rlM^692WkOp}Zk=beJC8J8!0ei9;CufMc|6y1NBDm_W{+>~6Kukqp3z^O#!68GGtAa;B4`!k?g{$V1aS*Hot z8103o3H3tDLQyyNzbnoD8Tzl5e64?v*}wQNi{$kc$Tu{xcIBu$SZ3R-hK=(OWKk`2 zEJgoE5TffPuWPHEDsWU;YgEmA^!A192yr=oyT;d~4G=@C6Iw95GkyWt7-yB9ZQg#)LteY{K9 zkO?$CNs~Hb1sO z{5^%o#vKr$kNhtweT)jAMfQhV2lGSmPiOxtP|yx{G%&`yxN9!eAAnR+0EW|Fy!3eu zU&Cj0O3A@o{Xi44$+o8=n$gR^$Q0FA>1W{y0rT}l!E|Q~H1hl^dygtsfSEY#@#k^r zTU%Se#bD8T{=uCb1Ci_t@J*GKuP~TMF#>%$R-}?R%Z!IpZe~2KG_4kFN{MqEM|#Ra zQ1~gi9aq|Yfgb^a`5Yt|lNk^o#xcOy4=*k0$m+$Hs@xM58mq|GeCBW`>YsT{=O7;a zOCi@01?g0;o(NJjRTvoAk4?zYJYcjcRmerffb(#*dVXTdeEn#*$DR9=dPlo-kF6q# zKg`evJ%$^^j(k@0oDpJd*4l@}JUL~mc-%1EyWVIS2xJAyO% zGhCci4)+&~jAw84h?1(TD^FUbt19-G5}(`9z4aLmv=SB-4JTlipu&1X-9|pbM&_f- zREYoiouP}1__x}}KN0)qPHDBtHfHn>LU;Qb(A~p;PtW!8;KU@DxL!V&Mrb?C&nrm& zMJdZrS#7kt{Q)~3J8x5AlAvS5cYFKmCj`A&d2p*poU!SPiO8{`u!0tYuKkeAb^CoB zLY2hjvbGzZjIxia)d-OoQm-P%knvckv01wAwJs+K8XBj32PaiTrx3{K64AsF-@V+_ zl};v$ibOxzIuylL!!`@mvsN8>qQ1p@a*8;HkOOAZ7cvrpe~L=1@~W;bP8}={^AA@E zu%(Di!vJl8EuNg1u;1U=U(tJ9@z0GbMo2?kvwcqHlhZp_rE1pKiQpT_=lb{MOPbqD zG)`yR^bf70m#-?Uz8EeH$eZs~6~;D)n_HmA43_D41tla92>xkuoxMCTWYt3bVE1Po zq}+x8^RUIIrk)}(eoN&nYlVo5Bh;0h`>6*D5yDH>QpOVa7@pFrPfYjs%WvR)=ZfgX z+MP}@T-~6=ut_zhCgyp2`Sr%& z?n04X&>9&^!Cuo%tDEC9qduosgEpta zIn$GqWCOIsjp?4UW87R@Qzp;bb3C{w2k7H4#*WiMzHel4gjix|n*@qh3-3zSPE*;DqSC~)BI~_I?V^u~Bdv12&)=*Gx(sC5!MTmSNxj56@-L8Aj za`II=RBDzX;!iBYJ+y1xU3R!Ckwd4jNuw(BH?c~38ixfZ$h*22Z(eQ=Ezn{~?3A3| z9_G5;?kg$r5jeZ@fWOvQjVBH#;ND39k5o{V&h2i6bT~6r;OhRnx=+#la-BlZ!W8`BO$w4&q~K}t}G)B%^atZl)p&ugS=IR&1zj|=lsk}je)^Z zSorX4<#tlJ`*@C>YzkIqPf1v)`|U(tRyV0Vw3;@SF;}y(_H4ESEld8o-hpy=X>l~- zu>(!Pc<@GuCYs~W@<%V=9KePBLf+U$GH5 zBO>5vXw4n>;&u)XGwzNr_BZ=1FZKfOcM1ae`NP0R$CJ-yIEB;jmejM;<9t%s+8W-_ zRRPsywc+qxjpgp&wJ)bFkD)x@n3~&Sk%{m)O+GiE3GilHdM72F1Ox~P`M=<3MrJaq zHA1Y?y1tT-laEk07&hctUOdfqjQ}X7A*Zy zQ5NeRe&jFAC1@$UUA29@zkd~+eRaZ)jfa9nqsCEQ>|V@o)>a)&pA-E1qbkcle?LEa z6(`$76nbQ&{M!D0n#JXX?SLMRFl%9&>;uxxN4#tv<15|hSWSLa$waw{D=+;-x zy(JG|Ti!b`UP;6--qnoySe>>acQYBY4-;xS)qZ3))unNEfr!cKL`;+vxGD+E- z^n8%27%nyMqZQ)eQ#WY~}T-e{F$ zX^+G6p_x`io`$9q8~bm6tis0dQp=aX^~L6%%H;$Ks$?za>MQXwb%UeY<%_5}Kn-T0 z;YdAFHzte8{MCg9Yce0HEPz?aJKa2d zJR3g+@?N0QV!t;dR7K37F_qet@lNKBg1(58>d$_Z>?ii-IK%#%P@=j_W(@}I`RQ)I z3fuM3Tv;SUvi-TbrqiM2*$P*-2i4ZsA%4#V#rn2?)nBfZ+f?9J7$5^3#3kW;4x5nW zdU;@DV^daU?X)|Uu&oYBprfW1U^^SX*ykhRa|wU42sm^zEq0rsz|u3Qj^rLxAmNf+ z9rx_=IPR%}Y2pjt zrdighH8NenlJC+{c+5}y#W>&$Bc6xSF3-3zv_ME&(%hNRrCz4Le6kJ~Ukv-;J6ei! zu*YM}T5R;2eeQM!?a`L=?RnfYpKNVm5%#aB&%8cvsi~KD!Ufhe*Jn?OmE|F}$S!lO zApcaZZAW`D0F|n~fxbN(#060PZymZV-#uP1_WXJZYJts&$)hPT8}4@{kKWl8fe%I8 zX{cv>OA(L$k7DPQL?XxRy^x*Jd1%xuTHqRSZnwt#nvnkSA6qnD8sn!t0&h$*P#>Q? zWz|)Y(CEoB{3@1)&=2^5oSZ1;rbBcBQEpj7^cPet7rA9c?dr^O5!+9J5K)p}6_v`A zPThIc&5?@WpVsgfjxO0zE4$2cU~Jadq@)&?^W*k*PvbOm&4Yu31-i+7#Wsuid6&}@ z|JdDXr=-QQ$GHcv5FcRt1~kP2dNM_wA0AR0A0Gn$>XYS-S2Viw7!1TE18&=%oAj?^ z`FLsN?!G$^#OeTro>{YcTz=E6w0d&suQeJRzbPpV=BB1tLmltuswn&WyL`}bg6nPG zy085qZgO#V{wu71xM=w)th4FeKu?p-L2?+cR?Px?r^8Lewgm(9h$5b?a2Zbb!R6wN zn5+CgPeD97nw{`{5>SIaKRY`c`Q0Cybhdj)!@m@N7%77;&GQpGCrs2y`(>uC78q-H zN$?GNrBHZ@s5V?I84CCcB9dhlN@bZLqFs`5v&DTc|A6LW?3265EkZkyIkwp2ap60Q z+Kd{aXt?uawO6`u?{@-)>}dzP5m++*eim79{NA8DHLE7`Amhi_%lky@E>Y6Zkr@(_ z1A%W}dEjv2xG7`NbCHr=qZS=ffjl_x|1~e(*Fw>Wp8Wvm6U6U6hf0t|hQ(olXLzOm zp(Y<`d&ytvIMsQ|U1FIm&fTLLSosbWLz$=fzbtT{6XKxaW3cIdc>T7^t9VV|=i#2( z^<7ZmfkK!^Scz!M!RTzqky1Q9!1r@}PNq`NN3S`0Qg@$%=p1^Rma|QMCByBYdf7VP z`X-NahuGJ+U~G@4_$AwM)As7@t}gG;e7js&y_u;CMFIP%bK~RuoHI=ZJ<4wU%~cM5k*d<LyDiBhr79xhBCp)4s`A#s|zu}QJ1)tqE|ZQI9lNaT8do^sg4 zQR!eVnuEl~hpiSg{wgC&NWMBI3zKm1C47rcYnj^PEvChd8%eGN=KMHIE>y_RSR z@q(cgZbjozr_-_%@lw_9Rq?g#iL9sN&0>UWfeNXBGmGir;%t$+p0W_!7-R2HG1mHG zv^li32+n*g6*hdRb}42N5FJ_iox(tBi}mFJ6f4+;`fv8D!?4ngghzC|@Ymtf9?nIV zdyAe7*Qb5azi@Tt9XAFtmUSz3KJ9*9d3(Jc-WmQ7X}0j=&BBJAzxBErG;U={^%KIq zBg9*tYKzP6VsFtsk#>1#iN|xm-++#cTImP;ix#_e;uaDQ;94LPT@~#}(Et7=phA?Q z)zqY5$S2DsK9;`{wO(*o5hN(RsZ0O)`uQk(i**o(s9up+d{{i};9F zT4Q6-N=MDEwM$4ZwYZ!xJ&rr3=BvjBpQ%z8Vltl*IuW)&$490~PpTm#0xaOOf0aoR zn{T{+15LQ^KD4gfHmXB{{d$$e@$ju9H&|9eVwBK&&#<0oV|^itG)3!P>o#bH)NGAi zo#S-Bhau_P>YF;T!m2OSTPR?x55UwT;q2v_x}4RI?%!zK+`p}ZJ=kr~-sCw#BMuVy zx=b>@&g8B9Ggq!$2VQ9(p&;Z@D`TYe^{~KRqw1>T>_DA9twTPG?)M``Af?|eX1>1X zsL8M#u7-<6{!)*Vx%_vNn+hkb8f&*x`JOLK;QP>64%A8%+Rv1_JFu*&sf8AvXfy{4WeI%y{w zN(|o@JzRcE9r_F;i~Z6x1K8b)xtvm}qbNF7^qlYiSsc^ z-btQZ#bxC*$}z6Y$ZKud-W0CQ)_nRzfD5p+n4KF-{%&KIbJhnL6#$gkp^c4Lx8ezaaxynNk(33 z{ks1pEO@uLHE_P z(S!OXdd?Rz6dZ7tudWS7)xk25k<;?i?nM0#amD{jQ>OBJ`scb(eaN=FY{UEff@m{i z{kO?)bso>pF?VHu8Adx-UnV_F+8@d+I_MPN#r8Ha20v>3#cH)ZF`jiHIM=~GA&4Yp z91e^Es$sLc_Y`w2C#+mhYq;tXq7jb27;F~75y@*9W8(1=h=7-FL*oQlB!$m>bq`3B|TeCojSJz>Y+3B zvvZtt-(suycpKDb^(}?Co`05ku%Psev4cR%=nW4$FlrTGonpQp7Jcj&clOJ;%4;MS zk&Dcra?Ym$RY<(%GTby}T%Dc)=SU@XKYG+FxVVe3&k*$x)13OS7oH8NTf6gG-E+F4 zxvqN?k2_AF_EYP~*qE*gBB;5Ul;t0{9m5BsF;qL%Q2K-{F?sa-BJL|~Jn4v@_VAFN zl{+=rWWL|s?%TJ%b1`Upcs|rT)6R3uk$%+8FBWxZe(k^1Vi? z?>zlO!R6<=HWt)j^j&rtoYiZoJ*ZgIDH%IW*#23Of3hoULt>`UP1&^+#8q%dm7Ifi z1nX(Si~AH1kg%2N>M&B)oYN!9ZaQ!GIkpQ!N>O znSA(lu19>1JSk3g>}%}D=Bz3O5pCZS8&l;x;{fA@ePCfZ?4fBlat@58&*5=2Z#Kr# zFHy01>6hnhDcza#fZaN;VBGv(^7?M9%r6)%FUXCIdw}{W1Y=_@mKG|-ka^`FXjs7)OwyhEFInz zA&Xe<-@JV#t{D*gaG|3hgTVaxgF5tc(QWCyziQ1v|HZapS9w}uUmUBZ>WdK`N=kk* zVO6?`>bA1*FeNNSMI2?4+bz|ZtkM@wGtN@R>yk7tX~K$m^6S$$bw|CLtoNl`q8MI@ zzf8q`IKR;8yWlT5pS_%F&ZvB&7D{(7b2Ajr6TJ_mw36jcReW0*A^s)OERaUJs%jTa z>4QxGqE1_dO(v|UD%#c0OP9)p9eIDXO^e&&jT^tW)PwLq%eqV#CliuoEt`I?Mwz>? zxSb77Et@IC?QUVRSO+k1o-{@HFA3aUICQq+E}^iVo%b?ts)aVh7wBIlyapu>#{#Bm6%N`$GTn;)4H|GTP& zbgcRQ=Y@k)Mv)ewr9*y|Idso?@ARd-+#IX(O+$Lg7Sdlbu@-oc( zOl`R6^W+~yJF`(bX?kMx?GT0|^z8zxP`auzYcGBkQT9(o$)na*o$JolzT#oTnI@@2 z0LJA0^xR=*ewLP>pK{wxz9)h>o*_5BvM6e?kwQ-i3#6UjULulZiaMEmHJ~L~AMvv_ z5kfGXTO#_)qR!szKbX$Mgq`pbx$;pb5hsWw9du`K3y+l*}HLyAtp2mn|5fMAn3NRrrft!P# zlw`5!QXoLKw!GtA`Qy7BP51WA!7f)ImxsqtNz+sm$PMg(oph$3my3jR^;HJl3n8Z( z!>n4ta#U{0-|kjdeSQ{cP=2keC4ctmY18I4ER6By&^8^8!_KLKIBsMdgTLP2m&c4H z_wou#tOlQEu8x!A7~s=j09rcm`FYp8(fq*9saDCpL{kKC|3dO!P2HXK$<~G23JLK! z?ZtK5b3ssqRAKQZKs@*D{#-lKtoK43N=oF}3YcvIWTp9YxiVphl zwr3#zLk`OLoy?O9a^5O5F$XCXwOyx`$GA?(6b@n}HyW zkR#^ycK7)GTS&d{D-*~-KmguIiB4;~@2!CW>m}W+o$Yup$+)XM$--iLb6@W=!~Qd1Au^siL+t1I~By|sxNSV<|Z%yF#DLy zciU3&Ugo_vaiiv3Eke>WET|%;h$eOMpMpQGNh-h8g~!>*gkLYyY0el==Ew3rJRT%M z-hoZCG#%{tv(tjHpT|>E?+GHqyE2RhcaHmL7fQ6+C>bsib^yc9y0jvs>Pc zu6h6d^swhx7DE(e%kpxoK|PU|5!kuf!lS1Y=?x0OGwo(~HVP?ZQ(EB|$sZrMIj|Ve zmxFupjK*3fGF~kvDe3Xf*;GxfO4BOe{C;NEW?^Cf$B+5Bn#8)g z*3A#fBPQk@F)tw8Amw60r~dIJCN}=`m-uNz@Y`@ZG+}Ram!83wS{?EZYzBNLHDynB zRY@VF91e)c*7_9~l<4>>VpFW?$i-cS7N(UPpqni!a9eV>lcQ#mDr;~_e1?~yXG$^G z6XNw!1`Wob?W&DAdqW$U)*It5u#kag`~wi_*EH#m32&qtsNVW~&T6hG-%^H+!}Ou} zU=Yo#bjOvGe`V7#PD|{jwomy6ecG1BBxk|XZWimO_2rtux!3nWN4+7p`Ue29`Y-1XDNR>w+UI*Qttl!m*C?YMYF z>4YJ=$^ck(CEU>#w1WB;$&BM!E2LUh*_j)(`{6g+Sixs5NKg3i-lc>oQU^hGLp& z(kBm+WqOv%G2G1M(?aL`B9$NQ{N8^ntWtnHym-#Uais`na>OQ4U7!=)omFX*ZIoQ4 zL?1p>{%(=)v8m1`%1R3nk^`%Uctpx3-Q%WR;bfsC?d!L~OOiZ$dN@;sf0U}gQgr)( z8B^3gV|lY`f#QYV4o|qO!@}(D_MPg%X%Lqh+GN4LEekWP?S2$ytz#}|hEN|3*+2qg zhW8P5Js`I4L2Xfn<+2WG4kQz=2&`A<>%+0T-c+X)qAHZ3!+1FZu16OXTjaZLK5joj z26>XAZxeB(*U84FD1yasHoL7moK5jgC$NxJ|I%l#1L4UW;zb=RM1|5R%QT4}Y zhAB5s120cQV_I5%X=#3jpr*pxD2a9Xym_z@AlEq>ak$)SJ=wQ7I5;&t96wxR^)2_2 z@wDFJQ8=AR=d^tb)1v}0e#EB<#%oqc^~Wo5iN5eK4;;*>n7FvaB+buSMb6CzT68$; zo162^O`_o>%|PBSb|!OD_N1;9Z1+$iqzcKX_uW;;!x7XS%yl`@AgTmD6ikflRo|wI zH9Q~iV-wUh8y2F5t?ALf9euOnO-Zg|PaQN;z=|C#j_EZ?V2F|kHa9yF$#5&%1#Ggutr=QCCVS+6TRyo8iDiJdpoF zhdP>}(fKrwPDp}{j%OJfe&6lDLrwu0(FRjf1q=;)Dry&793HO7 zQQ=TVQ^M01IyWXuBIv0_=xJOvEw+CpftbJo4x`I(zm?Y0YfzAXkdl<7VH8M+cV=T% zxc-IdziMc(+Pmp`at%vMOZYyq|G~J8*5(jb(vi&%i9jH{x`(=3mi>aA-#s`6oup{DUP0(83QG7^VszlfGqx-2lqOd|qDz z4NVt_*SjYvJFciYuc%5UMo+sd`#?8@8)z$>0b8a@9;MX3&Th*^=JTdAqC>Aj)k?FN zCw#iEyBpfwou7`FpzQV|>zUUEko#lX&Et9JMo_dbg$oObLG?6&gFx5-lR^Nif>Kk+ z2RNX)LBkS=p#HyK$O+7eFNQ$q5ZW=MFhQ>o3`7-dq5MDQ3@NKN!W8sjiPsL#m>2Lj z$ezxGcsT=y&OqC3G#s7f^5*=Of&vt`WGmJmZ49oR*m7_{(_Vv;6<7$}vxoT?-ELPa z0U9+aIxQ(v^fYD?iSO-TVg0^2t8MGY?T!Zp35<_5yWZ7)rmL=6KY(5m#0Kj)Kuq}E zydefeMBj{u86JRWEqM?&3Glgly3`}Z5*{4zw|1;PH{Sd#DvCx@648LsyWYFL9%yLD z{QUXo^>uh(fAs$SExZNveY&{{X;Tv-q!hUEx{)7RXB(X@goPi$9?N4LB?C3rqlwYR z=z!FEg$z+xY-lKD>S6CDQemORj0Hntkz2mhn+O`L=lVA3s!4A#3{_NU&FB?$t%nmi z%TD)Z`Cg!y^|Us?LMniRy)i4X-++5T$W-9D8$UTZI;^ihM#4WJEz!qFU&IhChSA?g zFc0V7fr@O8gmS($+EJs^;&rf~K`V*|1KE1kjuH3EN!G)_e6XVl!#8Ar(`a{db8mB# z*VPeiz2f*=JtEb5r(=M4AvjIO`e28}R9OF`C|mR5L590_x$<6Yf(DlpfeHt>0Ey z(6+RcQvUuWIG%dHZmb-@_Kt$AvjH~|{muVTN09aVkBei0OH9Ta&nvR-VQaqB$Dv?G zE7vO~l}&3H2p!Qw5X-q=T+I?v5)ioE=v!rNR_=Tp#$&4`=$j%2)SsIwL4N}5! zjGg!@>nPUukG$MvMOQxPk;z&Ipen!u8QI?Qj)a$QKN`)#f)fzqAruDk6x`L5#s2gW zpqPH7WRRM0Qz|FvLyGZ1x3>15nD{&LSyu2*g>e@*!z)Ny9eT`&eC3bM{hz|tSV~45 zU+a|!*PlxY{uzj0h+z~s>1Sj`03n{gz49B#hkmd-U5VB8W&!7`QF0mKV}W!@O>I$q zS>C&1w$1U|)Kbj~qu(tplDRUe{=SwZ@9Bgut6(8)NT6sI4lA+NLATCf**;zxfhWU6Gi$u*IcB=d< zN5peZuOtMjz(YVuk^SK@v+3Cjn}rLxr4!fY-l7GN7cIBxcn(Si9T6l)%Kr8QbyWD; zCr2Z?H23b`yvTKWHXL+m&7Glv2zdtsh>>OaS$3CSxug0Bkqj0s|CG*L$<;g46#@x? z0mJ(#|MX_{b$~ygsm{o`Gwj&7J2gm+=G}SpJOnigkSGuvB-h=gU-crQc)R3~mQ|hJ zTyhLj1Yq+{C7`!&pbz6d-G&KnTlnUtNYEsAnwC-@CDgvO`bv;jN4KKRK?eq+YyTAk z**@*6?C+7epuDkCgSNFzLvveRLz9ziwRLT@v5GwiVL+{RdNz6Vmn9z>FxO4Fztx7h zt5T{{ZKT9K&I?EyErO)UtM#;$4D$2%Hy1^Drv4VQ1TN8!2n3c|kFdKCNH^RxUAhQE z5vD281nYiUQEOB414+@e&B+9fBU>AQ?mUW!S4J#owaY*0qx(jFqT6Fc2oN&27S>{tQU70x~Sj)gA){Oz2&ekiMHO)WH z^m}vt@LGF;`8Pad0PLA1e1N8#v(eWq(<(;-P5=iMY0F>&9p6LK?!i#f@o~Khl(VKjb zi~ReC2;fuOE%COU2pPa1>{aS>6Ck^>Dut{>0htAR!L-`MkKNeX1GXPMv1ZzG0 zXu~*D#1rG2#8y4{Q&Ni0Ag$y+6u&W}M{X%!W(%HQR5PkIRU&%3Kw2@#=vD+wo^ze$ zm!8GveB@Kj1A~Kd+=taWGkR|qR74BSCoIu{9kGXKdodSx$>fiGSooL0(gjRUE9v(w z_3>O27~%b$d&mROS0)eqbv7Rg^bGgU;g9GAvG0%Lej`9y176d8AF;LFiryJhJpafS z=20l_`W$Ph1vc)7@ofGIVk6_sxl1_ld@t-N$EMNXy zf?AxFm6h>aS+FC;>Qh>2kLW33<)*fIp@D_pBIyNi^^T0M>B~r(HONA=cXWWhU{hn` z9(xfZ1U=Ky6VgB7!?=@{XgY(tOenPHkT?i=w%%(x`e^}gm;A||mK(Gxf<_pC6e&pL zm@aw@PEbq~5X=Pl^Si*Ou_5B7VhEB*4vyJdv-s!HE}Yd9AqLd|?YehAf4%T4trSLd z&Elvr#hYNgFm86Gypw?7HT?Z+MxOm$PtPJa%1Ot=?W4oOg~#DBw-hK@fV|V~kCE)^ z5+u(i1GS-tiPps~E(tRw)D-0#cQ>#F>h5=8^Cf3VbjN!Q4mb^P5Chv=#}{N-wW>2M zo{yl!_vJI#9NKa$Ea}zTvfg^9LlRuv9(!!*?l*;MUz9b*l#7~v{W>7$DG2mCcn85t z2i%E}LLi|(O4*E$Jv)~kHmU&x-S;d*Mc#z}3`p*iJ=@oiYxsE> z{$428hoG4R0vY!$1(ninD~mR+?8rO#Buqyg-=ElDw;eskNQ_MBj(xu*Xy9d)W9;kL z-rFZZO6vtzw$4t*hf8>$=C;WpPVfWNh75X@vT+=@^ekN;gt^eZIEO$gA?;&@YYY86 z%}3uBE?{`7=xuzj)-dCsTuHbfu+TP9-D#Mg!HLDWvfyGyu?7rAZO3?OeIL}ZeAbsa8`X< zPa~PWC=U4rXoZL#^X~1g-^NEi?>dp$+u@O;XTh)^uhBOJO5;V+^>K`677JwSB-+?W% z_Ewt%PdJKsp=UZ#ZuRA#nk4rlzqWmCE8{BwART7=*f&5UOcwsE!v=T!CxWt&(S`mJ z%)c@Z0^qHB5{Ez0)6b`rOrIXdZr-ZFL|*18uRrt3BbM*YfoAROF4^eF+A_vm*7XmxzelAPF1GpvCR5gN23F zX;gutz)F@yQ?pY-?b%D=@ZwwwVY?zfysZxc@tUJb08!UR4tWKI5}g*0%Y%j6%fqK; zeb6s>@E-PiD|ksjM~BdB^a+pE$;rvOx;kfPXNU2L(NUY_*6)l>XJbFfgaicz&u(x) z8;RDvli|{kvbmGxA@|`1uVy}=WRR)9p`+tPASNYv6#@n^adPr~YRK`~88QkA%FCB8 zL5nbG(?&)HEso`7WqF?d(b3WI@$sPH6SR7QD`+IVVzRO-e9&r3C_ZSBP2#E$@<+Y- z#?!M&TH=})x!IZM>B`Tb1k}+V@(vb0zWZ>22TqqW6HU#ed=G%(qoX6xQ0lZl2j2fs zoRX5l&87V5Q@1Y??og_LCunxKyK^%%*c?jU98Bae9wOr5;YlX)MYp|$LUUu1<;}BH zCk8NC;Y45T>`;Ly7&!+k=B4l7rO!(dcG|z)xN%N)Vrsi;u z^PNe7$Gg+RmPb(dMCQZE$vFV#13k!~zn*^HdEYBs?>Ri^>N6tH z%lk}q0l)?I{cCGq1QAk)Q+b_F!0Qd*(MSeXkC8P)gx_%4{OwfHamOYmmPT0l${CD9 zuioHTRAA0(-J%%{%A=uS`SUbY7Z;dN*=yIAQ=|}xZW5x8p}zj#yX#Zy`Pz>Npmp!t z?S2jDN8bhsd3!B#28ILBIXmCt*`mo%Q&Z!433}E&ZY@#$$Fq|Ebe1o`IZhK#td7pE zhVELcA{9EQFoNhms?2|#W62HFib@0u|6N@@?WIg@yxA#GR_DsK|6~%z`9CTH(EMmK@*7=obx{_Ee)K*?B!=kV~9|#-Cn7L_&ycWm6f2j2 zX5X_j_%s_Va2$Bn1@WOPtv*vXA(tt4i+wAMxcnpBOfD?nP}m`Hz2?N9j}UrFr(0$* zT;?`GzW<9=>&2bQ*5!}wL`6k8PI&)AB-TZ9tKH7rljr-oNRpiM51VVU#goGl<{S=# z;uv(Y0)726WC@@U>XqvKWn`0NmRwI4=9n1NOsO=C@MePc(#!t-vr#A!hi(rMn{f{J zv;ubD@j@wiNU;za&yOWmCO)9mR^kl9iNBc)7TQq$m}h{dPUHeSY z3=T&r`7VnK2na|^ON)u+RaREks$tgW*ZiodsV`i(pq%>B+1abi;^O)??nCF#g&gWS zTxsT8j4xiEAr&J$@G!Uoinrr`5g4D+VzL6hz1vT0&d`p<5qNthX69Xd`YHO-2Jb$q z+^9Kh;{W1~(bn%x3N?lUywpW4fdf@v7T1)Om4R(R+Q5Uk{JCCiceb~;x8%rE+`?EN zm8GMlB{OVri23YU03tB0_-9<9#=euA*xVc=P-fxcdEN89kYyFi#lef|m&DX#HJsO9FDx!z z{Z#%sA;F}W&EA!}%wp?nOYEaZk1)A7+-+}XCpv^v_6g!N=i!d&gc6eVR2T5$q|AQkE9purlZ42>S0o`eHa55`SS{p+%aR#<3IoV@4uiR zLjU$4iPZR;-OG_A62DK^T;iN_r`Na68tIXik;!rwq;QXlR6vx}Le>z5o4D@B5Y6XAC-Pyi&SCE}zAe;q}fw-8#)v zr^xF7Z~_($4Nc8}Ws-fCauqaXOr&k!TNIwSt1G5NWH7&a|4)kLE0&+U@V>K!?_5E9 zedGx&B&4Al|BYoFw0oYPkI_+Z`B;hrSy>UNXq48w+J@e^G81tOzSf;jZ=kMaU#)d8 zTa(mWRppx(Q{7^B({a%M+U%h0o;^`$iVPkfKf|BnTDTKR?2`E3Hzqo`h+2r{M9GjH z49=&WxPtI5zD1>XcYXaA%o|u8XrrKvq#I=0Ha9n$uGR&+$N9ca_2*UjCTn)G6aKy7zO5k@+ro|H z^M6VLP0DC}7?3pgZj1sWg@oH~SDbv!Fyx?s^7`ac)ap|FH^(*tx&uygwhW{1IN44v zt$b>?X(<1Ct#({dab>C>XY0*)0#--wb1B~EQQ_v~+`#%88@rrioE!U>O!eME(*t|= zLOtOEc7%^L;z|+&irnga+Vx<}ff&yTztzLMyg^x45U{9It7~iE9aU|uPoFz?F84Q% z(kEbOJ;H!}l;{3G&;@sM*2hPI51VNhN!O?ehjsPn+Lo4<&gGrYVWoLp zQo?=Yas#S1U{hJCKRI-*FE4nXh|$XM6K4wdKEbWm3$cjAD5JM+<-5ZD-gu3Qu(_Wz z;byw^;kiiNJC7bQJ^LUf7|gPG>&|#XPwNoN*yYR+qZ~7%i#Z9EUTKywuSDJEUy>2$z+SgBPy!Z6%*ifFBUwa(3nBq3v)YdkQ2R@s1 zIz}fGGQ2@m_=$c(jk?_7!_lv$Vzhkb6oiEA2VY$&3RcTB3Lh8Je+&i67}0ou!5(X( zp-$O7qZs6iJp>UE5gY1TjKpA#UXxQmg0OOMOnv)?9a3QyS|PopSExZaQ}aaL%??7U zqoaePI_Q^v@3I(!p`Fd^o@;;LCL{oY|Ii?&llhM z=!k%voae$=BY}~dn|trxlaJ?i1htKmiASZSrh-hLO0QW%cPDwh9~^{*?_y`?iGkTC zcD_0Otnfqd%{rAgobY5tH>bDUGp?otZrva>x3=>Cxi1+d3lC2Z5C7HCu!glK`q^k& zQXX!^BpH@j&Cbro#Kbi87T~W%d?e(yUWZrf>pnTgKHFRV9QWc=Qw=uzK7Fdfr~(dz zVE`ZuL<{0Tz#dCx9{p71+0oIzA>qD$edW92vZm*KA_c2^^J$I$q?Y|IO5|e@L@IXJ zgfR9*4|-AR>gZeqbPOaR4t92Nvm%?`EIo8H!SO|5rI4-v96vzHob9r9cDA&#vO0TK zEz(0Eq>J&X54)U%M0-=y1oEbnoFV{G&`^&=HZ=KT{J=IsM8B+F7bO+$=4WGLBSi0u z(4<3tMHJUU&k$Sy7+u_K5* zN`odX?bH!7I~$vj(9rP4G1O-+MbF7kv5DoHpM+N!)mYBg(+c8;rV87*ZmJeIbn_RQ zZVvnYnEhDBEPb#i+Ekn>sJeYRf{|GMqtK=d$Akw52ZMrw0QO?=HV97g*%&zhd_yNf2hq7x#Q% zid8wTpzwf;hDbwyH!ya*Hkg_mC#c)>jtLYG_PGmwVQ8*~HYN9b+q2P`Xp}oAE|{7g zmzR&>qWj<9venU{C4_{9#j?F)p2DoYef!qtRJRven;nF}z(B6GJyd)lR3ArLe&T;( zY!O$SIB%vZE5Q_wno@6b)Y-{Nd1FSJbe$v;M@*afSk~L!9pjx(1~SXVdJ zeryClwS(uGBO1|?I>{y1UUC|#wjB5?lz8U2;>N~?(7}T()#uNh!-7)sTQv;e!b|Xv z9yvHWx7!>Q;OBqH^BJe%cG1yUA59d{jHIEbcXn_vWV>BgJu^}>LLw#VXK$>n?PFzS zYD527W+8cv5!x`WH@vP|_yDsH80*cL%SaU`FaJZ%A~1{nY!0gS--UoYmOtCt6_!ZtuM0?4M)Z>^|R<=$<4 zL2+@hgt$1XxM^3aC*Hux-kbd$C66K~F0P-@kumY@+aW7`rmse~W`g}@H9Zb;r}|9g za2|6JmSKqMOcUM6E%MH&ODcLsOGg*ZpU_Ir^tH`s`2ZE6ufKn9Dw=`s?g|T}{{Gjc zrH@wq7QgAmRW(ad{`w_89=s!HaM0Y$Ys$yOON)z(3zF6H+_}smf%eyL-l#0TlO_~^ z2p1q1ibXc_qxY4mIJcY=dnj=)4JAeYE26x1T#He_lr!#Vd}!^Mi)@RL?SfXQY+Qte zj;ydQ$&Gz#?8uQLG3PYmRcNM`HAXQ^nwDO)R{dN(sLs*RjE7>;4uLFGBNmpChOgQY zR8irJJ5J?1NyGPP<%hN>DitC6;X@fiy*4W|rj_}vIU~JW3-j}aX6l2VK3T3kxKB)L z4vdpM7^8)WANF6dw8z_+9s1(~Utfx&-O2H@MZH-@TXjrMj>%TUw(Z>Q?yE&J^>LY- z22;1X51ZvGW>AK!U!Up|LCWE;R?4f(nWE79-;0bCmy%+m4aHM85OsCiAOXiUjaj3Nc_Ty* z9nxI;ZslPsf*TNH2xI2t#Dn6(x8{wWucCU&=Mna>ew1b3KE(76Rh~H`-OL`3>4C<# zZ;gZ>zO30AL}{-n31TGrXvWJSCL<#w9b}Sb>`YZW+})p>zrI_0slfDkLxcL{Y^#xF z_^BAJB@C_N@#BZtBavGf>E5`GC}01o6{jb{7WI&tfIMeiXu6v!xNW@kt(L9CGcnzq zqq{ve_%{ZJhpR6)(vI;u4ZdmtsLEDLRAq%RvV4xE8l!~?X$0mjKA!b53!C&o;$+K$X}F|;K_^0M zcBE!I|IM(Dfx$5u89}k<)!pr5F_10LXZ$e^0ONrJ$)|Y0!PV8oTjzY{w{PDdJ#1`k z4+;sfv9K`GS$U6!mX?;n5IuQ+FJFjz#Mq+@Lt#JkQ(~f`!#5_l)~8{Ya+qZ8kdd)oqU=f+i%ZvHK5%x&fBbu6;KEA%O9LhwR z7`4Jx>EK!|9UY&owF%5vhg~r;wAL;hcNmuJqs8dulP}Yq1sQL0CX)Ie#|_ImOgzXa9ionp{xv;Pr@uZs;XFNii9o) z8LHq~o1>`EpZ;9Ge0;o6B2^uE=#~EYOh{;p)5)}u^n(BBJv^hr#M5w&mnj@D&0h;m zJSsj*Fgt{g9=#4js5N$yKZKEg$$fomG>qr`3ky~C!NSt>x_*T-}U~b zRa9hTrTcd#Ldfmgb0|x#t#|+Y=9{ITcSAvA4G7p8a;=ew(Nf;tbVCxrWWn9paz~#u zjJlV~D$_?I?dRfhwkBU-yGTqM+sWwbLyJMctk31NEfqyuZ=crCRFU$Dh<_4BdGXN z%nC?qUneHSkpDV5Fp>Z!UMsVJOj{GIa{u0QbBM0r!qRe_&ast^{fyb~GkpCyLl!CJ zNl!#ugmmL}M881t1w6FDh6NF3@`CCvBhetM`eWu*C#Ox&lmUDNZ#CoaaqaBh_IK}~ z?;0-y>Fea;62IO5>61UqW846E!s9S<1ECeS2Y&?;vwK5{Y4CCg?(Xh~*>|U>XVg_` zlT1R#r{sR5(ecmbM4YlbRqpu`C{onG)50w4>+6Wp-J=zKSp9sB+Ph>BpjZO9pzw}L zOS@rO78ij38pj#k7ZDethQ;i4>QR z5Vc>LilC#b3n}h<(Q5Sm(?iKaLqlx?B6wr2pi5g8UE$2kj9IbW_}8zL)YREoSqwbN zkI7MX=d{0e{86X_m>3D4+9-qI`e2Y@%IqKn*Ft!k3}eTHiSWV6Gq8MsGORxQ?p=7o zj0ANJjhs9+ezm@4^o@OfZs~RtWFe^gx4rcUu zKtCVy1z(2T3_F746qm?EKmw&R*N%seKaWp>ida~<0qF`q&G%v;e0_4qXKCeFbi>cD zGA}PLAtB+-n-yKDDw+8WRc^rgFr_F3Ha0esb(=qE_|*BC=Hk~jHsFY5WoH{aQ8?FT zxkt{jV&g*~77GZ=g!zfoK+MGhE(TS=1CCIB({YD9L5vx-|2?a7t^pBa-YZ$@V3 zsEDZ*qsJMDk7fo+zL4gV#G=PCSD2F9tKBB_&CQdReT7V{tpygoMFxy6coPmU4M%9u z@X^Oai{}_mp|jlaIqzk4PrwhsbtE|_CnwEF_S(yZtUzlc34jv*fXn#D)YR0S?|v}d zbv(r}&J0Ws4idyKl)UTfTS8=F?% z;fPoFyZAD6+43Tvtb0+{A?A2v)S|HJ4c4m6=UN*xW;e|Vb{L2y}(FxXy*9pljs<( zo{nFnP&G6(w6_;B``f{cNW}a2DN4z!trLqin?H5YsZa#hNG*JKU&q!R8HQ`2eW49s z3(opZ!l6Tl0yh_^%W5$-WzCOQD~gJGIy<8}Cpr_Qg+xTc^|NF5g%7}*hS)h2DbX< zjK>X=V1HD{E|OIwmXI?eGdV&#&qCc;uv+QmWliO&|ljS5#0ypSAKmJ9Rlf z1{+{cR05R&(MA7;BvmwSEZX1LX#4Kbk*BAkmgnc$WgQ=mt32e4(Gv7iuE7RMLBU}d zu}Vsoat1H+^T}J7Xp%A&4ZcGCNp{8AXk!|%hXh7|s|Nqx&>_DMYy<)YHTlm7AYxC| zqRPkPpMMGp3y+Y}ep!MDjt>C;mhc(<;c%ffb)3$ueX>!`5~LxB=+%B}*WoXnITJ$; z;d?rn=H}*1i3a>JjBdQIN=ncfuJvQL<<_lRSdS;*7IEAg==^{vpX|=J(SG*)`A6(~ zfJ1J6;lhrf+DlLo*kM)S|gl#`){Py>?JzT^fuaPJ2*Nj_^r-^hMo#z zM?9_fJ2rYyksgDxPj)(OY}8#sre3{yld9w^CnEBFb>U0HPAk|u=y$<9e|;d_RNTeE z!Qtvv3W8`Hj3@>IDuR!H=6y!uV0J}|QC4Z`YJydOJX};47s&+%egd{RynTJ)y1H!Q z(_m*~Kl;vIf#!RQAoxRuLdB73v(VTCc23S3?1grBcQYS4&3g=I0EoZSs9TIQc^Mxo zdPz!4F9LZBtGK8^yWrI;_l>Z;Jh6pZ$Q(KOj{m0S=3tsiVX#F-%L9I|V;6AMPkDhk zl(_KgmnBd+-rl7Mhf7PiRjuSD5wq5-j*jJ?v*xubE+f@?yX8dxHOdiZZ9_Tl=(yi_ z8Btwq`kai2PfWbWe&q7%{OBL|*{(IVS0}Rvj}4iG3z%R0fe1HM|C?Aug`39eaCB^K zZBlKk=G9|i|;KML~ldpp~Z4>^9`_AXMV;R{)hdOX&N lzejV|+JrL_X?~4ubG1~&98mf~!VBvJZ4G_(7sN}q{s(=4C#?Vg diff --git a/ext/picotcp/docs/wiki_images/Protocol_output.png b/ext/picotcp/docs/wiki_images/Protocol_output.png deleted file mode 100644 index d8743db83abeb0f6f6ceba1c1561b4600650e83e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40420 zcmZU*1yogA)HZxnL_k2gq@+PWL_%7S?(Qz7yAc%WlvGNjySq!IM5IeV=@O(HzR7*R z82|Y9b)0J)&slq|8Bfe@h@!j%1{w((0)fDgk`z@&Aa2_u5Vu-TZo}`Sc$E~x|B#Jk zBt#L{H~)QU&W%MNC=pVk!m92mTeEJODpC`Of4Cy3%|V#M?SaikV$6A(W$(7FO09Mt zPwG89DzTbS)5Uigt1ijQV{l#nazJiL`RJB%i%^MID-jOLhb1~ApTYAc1tQz+l)6Xs z&yIf)ApxT|;D*R#dPH3AI*KD3=X={ra_|LqtL%C@&BG9BVA+7ix7~ z-E&q})<=&X!RynfPgz(Z#52pMtR1>H*VnalbQ+5fCZ`0sNeSS)f z;z!98lBKKCvcA6l#Gu9d`s$6hx3{jYu9A|{tckOW3k!TscsSC-u+UJ^6>X;Yjm4Ym znQ0G}mzNiDU?e4qUmgdoWS%qc>&~9GwzeW7BC@iw*4A4=4=5ZR9m@=&CA0LKJ?|nT%YR~fC!O7QMEmGw zbrKG^mU40f&0fbpQu&Tgb{CV9NQ#Dj{rWXC)2LCZ|97VL_~5|$>JvLHEiDz*!um+= z0}4S?HX_8A^mJ@2tTN~IVR8Xaj$=+(DJ4rF6`d+wtjEIF5CN|vJUl$a+lB_uow;U- zaH6NylWYnK3dAnjYHBX4KT-=dO6OXATWe|v5S|BX7=+OT8;AD~@50xVeuf%T0VQb|oAfo+3_8PPV423uQjC zI^IXXkt&I!#VN{2OVcTQzE~TgMy!n$PMjTX24Rv(tFkc@Y_1Ju^0{s?u&~g^_J$F# zOxM^vY}iDGzlbfNgkvc!-B)JRsjQ+hFfefZcjmbNNh=l^HsXbc$LSILa%X<QM)j>S8 zW!T}7964%Us+;@#lZQ=)D4VkO^}XKO+JfL|ao-ggs$fJoul;<)%j@~4Bfy%=>+E1X zJw07i!XLJnfph`a(%#ioZ;l!C z%=gOMOiCV>85R{aU-@dVNUKuN=YrvIUqel;T$7nMRbNd_O;1nn7;)#$9cpT76B82` zmu3ARVz{L)EFO`8!9h2Bd&Jv=1LwO<&P?)hauKnyDz>)UGqrY&Zab`}xcBeh-{0GV zxO8-Kg3u2Q3xm^wR|^hp2L}f;Gcym5`lVMR6BFI+g%J@EK|w){jg864$?#fT?XqZq z3o9Ph6^(T4=;*Mtvg(d_m@7Jkhv4Akyu7?rNO>L|9sP(sod6#{`+u&S9ODNS6%~7X zd!mug172I*Tn~wf*VoowTUd+V3{mSqD4k}jG+%__#mO$xx1UHJ9v+a=h%Y%g31<}T=uB1kkAIAgj!sWc z&&|!j>+tX}{1O5LE=aClzjPH81}7&q_t==2n99BU83@$4xyZKIb_PyQ3Zd6oM&CJHe^B7tgh@0&6 z^hZHN5Y5_@9XK1+RugpcDbEet5Z27u%n2+yu1h`Gm_c_CrtDMWU?#{25IxfkQ^}a*nV?`xP0e_J|9vwRp8bFS+>f>rOH1u!WxxNbck1ly z42hI1K|@0m^u4-R?*9md!Z3S?nV=ALb!d3l5)u%?&g*DveRFejX^G}g5gSQ~SNV#o z{f|8kF78dAU}tB)j{W>u|JX!ELE#Al!&;Qk)d%C9V1LN0rluxo8JQ=#b!=vRcp071 zk61sR!MFut>F?9GFU@ECO&xZfS#WI@#Du#@zUAK#YII2hljg&-1*6&!wtQz zudnAIVSzt|Y9=6{_wPaX(9qDtgxl9(?3Y29YN7ob!F^vw*7@AF(H}e*?CnigWPohZ zt9m`u_U=v>S(JDlJ8b}AT73NB-f};5lxE*+K~`4zrM(CFZvMl_eE>cJw#Q z_CjpQaP4P0WCnz!qrE-c!{BED_^3&!j<9Z=0_)vm|8~QR%j5a|l>sXV(%(~(G%=Nx z`_OqbN_0JzdZMA4ee3Fis=-xEDC%0LTauegkI-%Qj9=5tg4d?ccv&q$@(t#D4fNtlFvmSFuiQjpbP12*a$A zb#^qo=!VXq2Y1>aaYHag(LTwpd=~I3Dk>^F&Vr8fMfg1?gYBgWykO@g6FE8)vdi3_z9U6ta1$h)irg%i( zz(D+-kiYQ&z~O3_XyE*YE{C|nW7}+~-gN_5JAdi_m3cw#X z)IkU-6BazQfG%THGCEdlG?ws!oE-II8ciFE%Tj9@712HBSSi?W*GueV>2V}Oewbu@X5OG>-6;5%0RMc5cN0&8^lbR zN2*zW!qY_A3~CWobuF#LmKMRI$+0oDB^0%#D1g73e;cscu`P9VNqzVOMB3+jHFul* z=~e$K=na)dbT5+eIEqS0+(T4VS8Eh&tEsBeT(&5Q&`wWPzPe?&F`6%WZ}_#5k&))| z5LD~0_+|`|P$OJ6$Bp=KtL)|l0W_}#W8n{#8nm`vofUrh0)3Z`g~ew3SG|vq&txeq ze!SK9dURAZ-73#dq1%_={`Xr5AppfLE-tdN==$2_K9^?zI9Hc$u9LH~g>C@cc5_XM z?S@&|*+%{EW!y!^u14{9r=cYvKOhf}81X$_{`kTcY2_x}NuNFu5fOzGKSMr0`UxEidhW&V@84w~KQ08=qgJ2~ppFr7 zusIR6_JU*;)}iT$hKj0`v7V`rCTR3h?b)-N^TsB_%s~4r_=eZ~I}u3rjH|=Gm4v53OERPC<4(Mc>!r9ebA-CSzM%0}6zhdmpb?@$?hF5`w_e|7cr%9VRl zQb-ezXB9>8QySe|T}xVOG##a@K&GF4#)5VWNA4Qweyrl9lMhssJPN5?(LG~hu@Ml`Z? zBW-OjG&H!MJyZF2CsLFuz~3JU85yFN#NeQbhm0|4X~`6Uby1Pg1FbIR)2FrHzu#i) z#3eN}oOOi}3h?s-Mr?K2R98_MSxJj+H^jroA9`K2aILDUT6V)ZewearF{{J9)-2+> z@+ZoETTw*-I&bUg>Ct=}9gQ6??c(fQRa@IF-G+r^f#CWMwBk16;lqa>C955ayHH~% zvSkQg-dvrmdJVdD_P4HCE;I(LtgZQh@OV3F>U!aZ_Wd)s+#eKz3I=clumPY89Phrv z%?Y48z!`Q4Aa^@kTKoe8abUZ@g%jUFKy1+SV&xMHdOt_#Hn}TxEb@@bLq|6?T}t!4 zA|@eeaNk{c`}XbjY~#%IG+GHVlOD7vwL*1j@o*GW)Oy#yNn3qa*jn#-tLuWDFDHp9 zIXIjLk~qT%p9s4D`x1V|{7~js$z8{}0Yg9>0FmHw+*Gm!v{6`S<>`3_XUylaA?o}b z!?0Y_+}s@6IyX0=L8ZnNi*DUN;JWu7ki){tf0jb>LggPB9){Q5dx?pOP(&7fj(DL%~&(!?%a|dW6(d((^b5za@~2hNdB@nU0RjP-!8aJ~e)4*Q&t-$OkFu(|y6s#O zF@no_@(bRRe^;012sRKiGVVl2O2yIvQ!t9UytvpP|B{`(ytcLmJs+CD)>gOxl!2Jp z(URv7N+thYi{B#dAfQ_VHif+ah$1E?21Odm_Y9~?G6~Gki!rAS$Sj7+66fK!Z?#>V z?k@|ihxbrKbwA{DWkxt}O)6>CBmoGy{T8+yf)MYff-#vvRLiIG%6(!p`a50y>OZLI z0mZi^BbchczkjCLs}?HqkqA^;d=DkFcpAqMm1vpPT`|3v_}-L`X{y%QG}c0+(A3_Y zblrL3C$^0=5o1z01#2n?##mOSSz(H*k3qeMAEJ}CJ@0${ce0$i#&9HGC3nLDPf8b^ z(o!J5!9!&&V1M^qalXmp4k9u#QreB4c34xFm9WwHm9_Q7<+&U15J^u@Uc{%wL`Jcs zXru^np#PrxD;VW`15$TC_BVU%)72OVAY_v`@-s60*1l+?MJIm_)jf-thsIE^umR`{ zS{29!aFx?qY<^SZP7l>tlDB86hb%omI|K4=!dGlNS(g4;gU0p^FSOi;+_q&?TYyYq zd&fr@V(N%Q=~Ny5QsFQ~bpx))M=)&RWG?8(R2;O}%y4<@(1H#Kq(YLuLY(RG<4#Mn zYG^Yym6e`Qcrg(Fd|!y(8XF%6*-O>HfC2$(UQBFkNMxQER{eTDWqbDghC&|Iv6PFW zqqMB-SMu)eZkfGXC<}!3xVkbwdV8hpbJZ@`qDv)zojJR@xlo;U) zfJ^`qg5!2Gk9vtND&j;#Pt+(oE6Wgn5i;fEA$c^}%{JXHI%3&waNwG}^ybQ4JywCaHT6h6YfpGpi9lu5t9SHK#FGws{6Aup$G*KE}QhaWJOk!aK zP;o#`V$rEVx5Cpsv-y$2Gr;4ksQ44g8tfum(EM5dRD!A!sOO5Wy(GW(9a62GwVG9{ z0;zSvVCiwkc&?1BY*BuGNJIn%I{H_Im=7P`vRnns7gJW0D?N4I{^bFD6(j}$0Wt$; z0tAFNhyt5l%YIYwy{0v`vm{H^i&eMBbEW3IGNngJ$;blwe3g}z{afln&=s;EZ1VH- zLC?S-eQpoS+ngw!uXh4&%~uO@l5tn4fzN3+@NB=rr?HY*P=&8gSJU=%kqd=kci=74 zu#-^3nwy*RRV@W}lmQ3>@53TvA4Y)>1%&}&zxWL!!$ir9idz7`_8^(&fxnMwxu(;~ z_x7WgvlV7xfq~-hAH6$)O7p;^ToYv24nYw@7Hxlp=1_03h4Ea#R8DSgxrz*sis8Y* zdAUk74o`z;{K`qH;Pq57S<> zLC#!M_?qBuKxv@W3YZ@rb_69Ba8J+o?{WXWv#Tj7?f!0m|KS5xdm*16sE0sdJr6fH z&A)#Fg!%-I;=06sfKO7iUZ7Y6r2K*KIpIHv?K5sHt=`G^P-rAWr!1E{K6) z5Uao{Mv6%fx*QEn7MucL9kw?hI6WZYc)i>gPp|M9cHl$jRbz09nudnSIqL<`Y0+*! zj@jXCnf?8J5Q2~~N$aeqDv+ZjP}PV&tH9w+j&dfQoEGBPp*8#_C%!va#d zj1!0_C7R_O)6*or6UJe~0zMa-SGA~*{5!9idB-Yto4}REN z1B3aoLJfl^_opBkLbal&&#kKBpr&4gHGwDwCtFxrTAGkRaE0ex&LASGnMTJ4K~2GB zO?2cwS!Tqp?a9W??e_DFFyc!|iO<2Bl9ux$20=j|kkBT54IVyBPUUk;h>PoKP{|(Y zz}*1p?beMp{@;2g>Vyvc{r!Lc{tXmU(s2g)sGJ-N%N{}>@Fys+#La=895sS+ckSzc z{r+vZC8TI?Ul#89XV)F>`fJJT#`?MqFdCyL(V^dOBnlS(bciEt1o$>G&R|_Q$^F7f z5YKD|!~|swG;O#+4wB-AhNO1GwT%suhYx3_raau;oj1n^pc{{la?sIz15`9J^6b&0 zbksMT-N3+)x2B-uJ+mCmyK@iI5cLZ!0MtFGaDe)O;)NFvGmAm);L^zk2L~hGLSxvO zEbjz`p+QeFy5~*Qay_x5%%pogxh$Ou*jzF)VO_>jCt{?+aq*-vM*x^G5FkxBuHA3f zYxMy#L56@(W9S-LSzZRA9TSnK%G9DCLWO%uckf-;!ora)-W02?f%u6>sYLXf5Z$0c z5C%>Pes~KCJ$p9N*9RoL36+eI84MT%!{f))yjV!l#b@I@aS5O@AlhnzUM`vcs&jz- zLwXDC2pkouIo4M17L&QqJ)yxpTKfbSp!AL zv=;~P=!$dJ>#~Q9u+bryNYU)%QMG`(L1ppsItSzG@sO9Y`qGCg*j#kP$%1zBF7n)tIZUH#bgff_hR zP>5W2ym3K#0M3T^LMdZNrTnfKl^0-oyY(ovMEN&Zjxix7tF1ng zo{9L!#m5^hzF(Q|t1#|DL)beztCrOBVPIgSH#TW96SSmJ1jg&w-2qg0pm#K)c_V944NLO@>0nd1!#C(NLRL)nn2}c>db3ath8J z+t}39e-_34aARyGg`Snw_WJ5FDJcom(XJyMMFOZD;16S4pYAQ+=Q8gA4eHN>va$9J ziyKMc*T?Ao<%Mo;O$XfnD+!ov+W#2@9Sut53LF4H?)N+RV=0k%XvqVtjEqA+e=08Z zab}g5MKid%kiL5TIygc%ev^es&QWq22*;hbv@!`j=})psK%Tn&0v40(6a!7~PFsdp zSQdW#FH!-|DkxE)pXZLOgZ&HGKLE-mCsLuzEV9V0Nj?Rm855yhYb)nW8GP_}u33jI z`M0k+O9KDZbKrRo5OW&yx1KzxXaq3UW|df&YW z6{iG*WcW?E^ctM&?f=}q(!pwV%j|J=IA@oRQS2)2>{{IiEVsR}!Bl7L3IQSuX!Pz| zi;?<7J#|#;7|@9Th#c{zsdWw0u&sO&D{4_ z=Y(}?-$|>1} z!4>Bx|JdL4anH7VY4;4Q<>sa)==ZksEi6IXOW}j7kKM~pAhT|LQOT8;6TIWP7z^Ba z)L7)Ib8+|TWHBl{JUj%K9)~RK;LXL!QzoXqo*v0OQaoYRn3NX9@5$T`5TM61r)@9g zR8@_RjHu}7%nS_NAWw+ZZ(RCnq<~35D!BI+L=(C+2pePsl7_i>R)8!Wl(NOGsY<5P zzk<)76Cun8KNsibN;oqI7a7t@?xhSV>Fyp|y2*jjW=LDLXOZXF{#_DITp+ zM`!1)Hi*%6Tba^%5cLs;P_CfkKo8^7e*($|pToje0I8r2W8n}*b?a2U#zuVl^a<9@ zwW z(p1qP7M4*!&wx)N5;Xl|FM8k-Pv8aqKzxJI5WSpT?~{MG&fUf*CVVeW z%2j{V`(FDXh&V0dRDX!$MWd=2#TM4J5upbrCKCJHS1~ruU_L6es{o-R{i#p^U(e;_K zQuD0=PcE4YI619XT(l+4C@?;Q24|_VWl*A_GFOCU2?O*4YWDT$A^4YqU;IjF}o>B%Ln-Vv+Jv4 zA@7ek>wQ0dj1LWgGz)ya;<@k0==gYvK`Urjb3Hw;0g!8E_M}RjV#uA|ZiBlaBPC_P zla3-6Fg7tMcjZbJu$$w@#fABaFsRKT-_=Ac(7)PMY9DKP3tsAk8DpAg8U#r`BIA?Chd^hdFO04@8EBPPh8{f>!wc{T+@F zQ0IU?x&b#%PJZ0=QH!t!H!U@l>~jXn@&DiZyTO*&*h(Pz>Fc-H|LM@GG&lN-K{pE8 zJovcJh{6YwxdAAc{Dm1O;5YqHF9!z5_}$C=QO71G2zAgV!GZ>Z+~pkqVyLfg<6Fc- zYc9TL&wySg9(HE}9^klaGh~C)5)&V00HOUxGY3#Aqiq)GczMTrbXXGFh;>FQTcA=0=og>0aEkVj6+yge}C-u zDM+MXvzLM6f{IHArcNmYFHnz3Ghf8d;bC?zu9~v4H7Kzl#ZDCKxB)M&SCa!t9|X!< zZNNYAmv*|ly0WjHaQN{>aeY$U9m0?8{i+fd8;k2>L?tMwAESGBp;il@7v0MchKm4l z7Zow5&xeKwiKLIlDkf+8USEmq(}I`;kPKuuzX?WrfEF(U(RtpSRpI=N3X>$0&U?Oq z%aj9I2AEb*Q1HY}AMtvuU<~YVXd4&c?!f@W?as$6EX{BnP_=i7wPBD0Yz7=693{}( z@>Q7-;iNpu*jN4xcxWvSjPk#JWMa^%w#WV!Qf9!rK-RUUEke$`y*pDBy0rj}EK?$i zi<1-lHgNoXF7NR{EaLZqc>`pPlSu77c*%jjT6n$RzZZcJ3hu%j3{!#Pybwn~jnrXI zJS4Z_-6fS*2WlVWX%vN!{@TN*A)+uZa&&wQNxlwt#f>JBl|?gkNncb_0v>BKKz6^o z_o0piJ-H8>@yhDz@xMQv1dZ=m(+0244j7rtu ziDUUpB5!wh_XI`F-aauc?TItf|5csN7Kwpn{tPvNIET(>&Bi39s-|WG+VJBi${HGJ zye^hdM4&NQSXjvT3{oGyK*i6sN5$`6b_7%evoudZ9Ev34Gpg2xXf2ZZuzfKo8G z16`M2Kp?=i3kENMx$wJg5i!-Zfv$!BFqfAH0^lH|P4a(OvF{cxMQb3F?dnht?I?&I z7bF|78#KV%YgG=9j^>&?p1p6El#zMJ<4EIE05AdO>cDq}c!vSU35vm+q90E5=%f&~ zUgnst3T6Sme4(^g zr$!MAuH-h_B4+>TNKgOsG<9mM0qeeIW5TLTwFDClYGs+_91Obs(Sre!`o=~ThB(-B zaZ%AxiU+a19M7J~$jg88k(HK?8S21<;=VanNO(l})ceFfU8V`ePZ$-SenO5SJF@c+ zO!BQRFXIys07-+Y2$2ZmW-um77b}%JLX3_Kcfg+Lk``v?E|snb!n8SXML7CbuU?s% zEknOwUuSfFd0$z>#pN)G(<+jbr(@X>6s8*`k@%T;-chR#3<5z>07GU&NOpWC-*|ri z>U5O?K_uwy4j2pG$gSo4b#YfdO|Ti}v%os0rp^TaByWk!Nzw_thBD0}kby6*niIl) z`?Ed)3{c8vQIwuu?!Ifxn=0?@-1iqoH~<^BUrE7W&v>c9e3c8W2mc)GFHCIU+skCY zEC!^>D^pW+5CXyH!yqp;_SFKc0P__cSGYhsQzy}cMTZPM@YM2l<6rmHCc=zXSgCr{ zL+EWo4*4jMAApOkZ@ocKMoU8Hn}_L1h+*19mTPDskmpF;Y@l-mkai^e0;XVXW0SAC z0dSL6%TKxshiL`EUb9>oSX4!2C0LY7cns+aabA5IH}Vvi9@a2kpm+|2sO`Sa&y(nU!_<7PZ{wxJrP1fkg+g~(DxgPi`FLt9!J)OT5Pb2`^D5Glc$0h|S@ zXai_X9s0;r;*hB?Uc69Nj){*S119k=5jBf;WNfUspum_tanisoOx#)gV|`N-zjuwa z{fC0wT(`X?sVc@2W;UX5$OsnwraEZBF?f-{s^wCi??O(1<=hpDk0|pxw#_g=qSA(i zmzF-c@n&Jz0hbI@gr7M|`pvGr*=QV-)^bK}E`U%zJ-ylZ#~Kw=TkvTRJRtAENYA5} zfhZ-^?=c9Xtpq0<*KTyTex2 zRhA|uFAXmw1%NSZ&$kLe(Rr*BU`Iy7kyzv5Ve)^19KJIoKjkdRdu z_$`olQZ8#vYis73p}T%n_AJXJ1s}j2baQhf2!p{d8JJ-L3;rq%#_A%(p_^CN)X?z~ zWC?-*1XUq4JRBVjt-)~_ZRiiB|Io;Y340_8vzL7-q_t~l1;OeG*$)uXB@DA<9Vfhe;a1JjfV){a2H zL>%Iab%AJ(Y~sSk#@Xfhad0q7hKX?SJMp}_gk;5AhTsRM^11-R`W%<@;9d|2LvBu=tBXVsrKOCHzyDl!2K6!c zU5>W{i$MDAHZUt;i(%LoK;uhiW)wrWBJrD8M4`%u33mh=2L}yEM~{f4^L}q_@dLPI z{n!YWKit(9Fi;Wp5Eusm8d{KbqzGQ;wHF|_J^hJ-KOsWsilwZszOu2Q4VV(*7@Jxg zi%dT3+p;4}FM-AgCcj@X@r;N!ObkGRgH8MS^JhRLN(p=pFie=5nhM4r41hBnx=LG zm^+Ed$N!ZQ|1j^K+_|r?65xil!kcP6(%q(OH(uW5J(656d#pFRykd>2@qEQwVMGEU` zfG7mW1rwI#ttvPnqmX0J#$f;in{5377)fKp!?)i;8;1Z9p@Grr|1It6g=X%HY`VImbW0%yUiW;{aeZ(hz5B51_@V>~&1sxVd+s(RRn4=DyE0{9A z{SvxrUSJ?HqDZscuZ;~$3>J%y06{?Xo(O-OqVLT-3VR|nj_8z>|L!2HtAoj>xVZR+ zG&?`vdmG<>1mI)46ovrdWWfGM+7txo8$>l+GO~fi-6aB3DJj$=y`cXFKYEG{M2*t@ zLtmn*O@irq%WyPL36$V}>&^{PQ4bKH$$sW@i(Ioe#nh>_f;rzq(oXYA_C4U0u13OM?bRZ{6ZDr;c>2+&^tC#AtK@%__r z*SY|lQaA8P3N$zqQd7av_d=kcpuFxFfm{aeEd(-TI@xDvz)&FefegV!BQ;D011(g_ zy@b>UT?fXNBJe40y@jcMXa`F?o#70EKtf&{-NT-=u7R;apyps-gEJ-U{2T@G!pG+- z6#sDBD>`ba&8taL6$CVnHbae@3^(n|Ov; zA11h=nElU1PEIZ=F~KI7MnOyr^2!yUf<1TsH*YRsvmgjGL7LCG93LIc%E|)vhkqR; zo(U2Z5eW&1(zo71l>vSQD|!F^B@jxa&Cgh(q~Ih&u4iOqtjLz+A;&3pg+@khgMJ+# zA|)$}S8)CU?^de(&1jRR<|I&=-FF|ev&~=-x~aLj5nLyTmVhL^-}|Q^uY(l>1CQc> zS`hG%!cCITlo`DT0~izoN!1=pE`i`(9pA! zT@!C_{^S7yUg*UmLqpgyB@hH4qNp-Kh3*?3j*-sh%3TQTGG1Oy~@w#~6E7$vDbX&&>6cI{D2!?d78>;~n zY$$2Lp`jgIYA@pM26cj73`RL5lg@@O*y~@(N^^3|ZEbHxq~KYZ!vC(^+#mx3JgAXf zrtHvzV22WA&0#m8xX*Tuj*ZPcuU&sNQHtM+pCv5j8PHS0!l(J;lE1dM6i*n%|0dc- zk-<`i%mOL^l^Ymc^qT#L72|SEA?3~F(U^^xUlqC}5edo3GB7#MK?36?dx?yAq3|pK zToA+X7z~6BKsC5xOX=q?md)=d(6twIsPV4w%59Sg2OAq131<$02&IJoP&yBT4;mCe zWnc~PcnAO%iO<7}V|#O3Ui;RImCIB8cb$kn_OmcD8nF>ge!+eCc6i-6T1y@J0(em1 z`GLR+AWAwLP2KdL$3@Xct##~m3xyHKOec?&!2N@|)^F8`KgF4zUkDA}>C#YIg^3Y}9pU4g&#g2u7soAzVTV*2f-v2NroF^&G6@0t|~# zjMl^EVrRBC)fD@ofL}A6GrjPc3Sa(CDhdC$wz)R12)E7M;%fA2QxbH)9?Yb@u5^DU zMqq-V9__m~!Q37;*?lT(!Kmx)e~pp%9w z5MXom*}A~L`#6w-Z2PIUd+MKq-1UmcTf(Lo|6v&}zw+{3NaI_EfP^8c0I>#tGjgID z7fac4W?!|D7YOP-BVj@~8w@v}$83+*sKVZOdT+LDo}rO_IOGlMT`8DqRXn^U_cCB$W>#HQJ)5iRK(Ix1@{>$j?FLz zK91$Em#Ec4aHRJzNMNY$=8*tgvio~4FRD*6i=%u5_laq)G8247?kZ)sLX<91Ap22P zyv4Cp*_vxkmZhVB=L~7ZL{Ay06b_g@Klx5Zgm4qx4Hp+s!kkdtEbwx&yvp@Zaz$h0)|P%hA>kReOm8VNUP}+w6p#}A0+@^vHhL6>i3E- z*!TZREAgTjaJcvdetZiXvl~K|zF?xF^J-#%u;gK4^??o22AYt^THjS_F~9Z>rf=4G zctk!n0x_FONXN~p*@&M=9-=P9+DV}V=Ia`{Qk(%nC_BA-TFK3S%^ykAn<-F1@$qFg9% z{dFGk>jZt7qHDH_cXW^7={RSvX_RW!+yp1ILKIYF;Sb{NmHEY$RrUnbNxO%O)DVK##=yXv6e-@mv8qXMJ!$CDylbj<0u z-|D9dTP{D0Q^XccM>SK4?%mCW+psW!hg2=BxL_cKZ&e;|d93y)8Pz?oyzMrv1dmra zV@4&plFu~lwpk`~iK1xv}w)>fUPf34r3|EajT{=cim@PfSdYYp|KeZ_+qM*2> zrOEEzPn}Lhb`06_@aH7AP}FK0tAFC_${VS+Kg1%94?tme^+rHJ>X1*Rn(XUZ^@gQL;*qLZZul zR41XU&DG_e%@&RT)vLSbnLM-|wF%nH>(cC_ZF7T`blRiYdV95^x85ebqbs*_oZTKT znxtw^=*uI`MBNtcdQT}A_-4U@hjdJa^k8^_<(VJN_nf!0LDP_xFo1pfHHfmp@UD8L zQO)!q=dIHZzG(8hzptO<$Gqhr%b9t9NmjRyD%dOV{dyHiUd1rf@cwVs{G?mLqeBBTE!c-Tq9v{idhyb54Pm{2L!J;k}OTY$y5%E z5bmPwZlG4hzmONki%FV}8{51^dGR&9B10sj(}MBq7?l?5CfzpUC=b~tYcZwo*_y2? zk`fEF5S5wjIlVW?m4%;t$>xAWvxxn9ckE&n&HT}YIyty_k=CLhIwGk;IKp}TsEWWc z|4gy1^iK#skuV;idf?P;b!kg1={#kwzqN83BqY~!C^9m^w7djk-SP~Kr!sY)^_V3b6$c{8E$_QSq&(s!!0%q&cdBhd+8&$_ z8iLE^ePe@f40Dl+GK@eP#IEr`-`zht&|!pHIt6IyUOBO>cpq{qqZ{fY z4ezJ*7oI7;P~}JQ8x1uS0&0aO4PMchLCQisBSww#%zZc!bjXwLjBK%QTR<@CcRe+MTJ@wZ#buidNhC!W}64Xcg=v-p20A)m4g>8CB3=q z9Gv$*RbnAn18tR>2W~Hi$14_*R7;8+Y!nG=o-ze}kc3AgFr{!eG#_kA7!j_VL*@Em zv>tpbgkoNx@o=K!(cC-zNGtlY)tooon1#jpJdJNUW$j86=k#CI+T|6WI!KV^)*Ou{ z{LY`%89X>TJOBQ)eFW{0YV=83cca5a+r_)tT-SYmlBS|0H8t*w0F`kX`=9N0jYPaE)%X55+3owihNo3j$fNA) zApXAHV&e%qZ@mMCtL#b0`>FZZmz@-WfkNM9<6uQ7WmEDuy z(R+@6%xbwGuqkony~lMV z6Y^P{HPukHZ#!;OA`~H+_iaTe@U}Ld4GdmpE(nd6 z`HqIf4Wlt{k(PCo%=8}r?sW$oQXiHuj&^<+`X zQ)-Mz?0x<~WFh))bBQ`lMA{V*4{gzg-RlSzQPeM1dCwW?N9Q^v(xzHkvM5`#D6h9_ zFq(s+zD=Kp6FIqde;e-bgCCVM+`qf|YAt+MzwcVAzj=A@?=-o4mKTPlfuzES9^f8dtB~otOD*_yrIra-V&?FAGkN?KH!s z2{PHQ^hS4G3IpYnru{W0zN^Un4?sD)ng@WwoqkLZN}oeu@&2adQCSpjR^_5`X3)mo z?CYuE=HefLFZy)+pO_i*p}`D>stvQ!8E zs@n((+0#nGrYLu2=MJOR@09uZ0jx<<{k;{o%cOOpqQlj$&U4OJXW0U+L1gH65raQw zxjr|V&u(@jOzHcN{BYiqXq$+PZYk|1Zk&qgVvUO84JQ#S>=-6f)wYbrH!Vys9d&~ zRyrOv_lKf={3|f$b;6L*spR}CG-)YaBcSAS3`X@Y3R%^}!rZ!o2Y2&Ze_>lIjf}m< z6~G@=`(y4P8o)w4_k{j%rrlS6lD842sp5>>97AOyC++U8HVn-d=qfoozfUMaejCiH7nPg5qb~6X`sp@+vz{n%7KF`pfRy#52k2vcxo$qm4uG!9zZ? z{>MQt+@PCRyg-d-TO?$j;AW2u^SS&p1q!VaB}*}ZRB$jSijs&J-a~Ch)F2!tqXTsG z^5v8te90R7YHV9jo;i?Dp>evSW3)FGYG02E)OO?JZ%AKiq+?_Qpj zUy62%ly$txu#8sE^MSWRXA)rvXQ*1H@ME|Yrx?O*^4FYQ>+((S&4K8B)_h#FE2tF533y(3RG;Y*zj77mu1 zplislNvJGWq<%&+29zQL#Pml~&3M+jZ?*^Wg=c*v&Y=49_FvJ5LYZ_=pJN#~(t{QF6g9@^o%kwWi# znHU}SZ)?1opxT|iK&(Kfw2?EU=-cYvzXWYV1uFyscpzkdg3vY3q2CPmLC6@KWB^_YS! znxUyEqJ~GJtsVRE-j2c3>%A*7fuP8rLnC%4Jbh94PjU$I&5FWkB9lsxvx|v0Hx*{? zu+1%n%H}l{Xv;s98JT;bKg3vDkY+`^`VyB&kV9x8`-))I44-0TI%DC1e_h$j^fc{?;6$cV=_HcuAQq)VL&3qBL#`M)xo9UQp)chTG3lY6U@ z5Sc~qJ;sDKK~?*SucA_nvBTlUsMpEb^u~tJu`NtjPAv=^=%gd!8poRs6qrdJCW`zprihAPUkY z4I;-&_2m1BrK4wyl+!bz&qc+YyJ4p`1@yt-Q+vuS9cqEe+f{F2zm2kfRG42 z8Z@ea^EWVWQB>ilu`JAQ5OU`X_YzQf2ffSwCWu(mavy-QT1 zg#!o4#2c%#z7eA4#?4_ruNib6kMTkH07Sap$k?Jmz6(;!dvdUwHl+97!Rh#5zhw6E2$wP%^Q%4`(w&{t_-^GH<1XS^XEesl@<8l$)hq9}mMa%b zYxj@sIbI^}8L}|^pRJ(ecez=rF8Q*P)wGJJ)&KRywfk-kk@~w*CV9O7St9W|r=Ff= zgC=Z>a+z@kVH#U0Fz<5umXw@!H$%Z!{Gy)jl-XWe!UwR0gCWGCI>I0;0gJDZkpHR! z3}Y9O`|g4)wTW!X+6coz$S2_8S7G7r{{GO4ie6#CGsJh7ap#+1+f`OplNUr0HrC?( zgTMb?Zx98Lk}nH{f)A9ueySAk!i$<;d}}3K(_)(g#QkBC2szJPFGTe+_bdNRO%-)5 z8EI=7X$A-ct(F3F+Jo;Yft}HNAC|_-hX-MQw93l-`0}bo+0ryxGczaGch#9>WLZYt*4x@zMF1LNY`4nF>Y9znOJA8E z;d*glAnfrTBwWMV#KU~RnlgdI{1iXAfD)4sTuNED0vc0;;;;URkqQUCh}cSrF8 zQ`NJ_*T;Fnp(|?yM|a`hQS*aJocv@*FJlzQW=TW`ajHw0Yr>v>-GstXi>6x>7ys` zVT)wLDCemfAT?}2_&3eJ-GAXU@yGaoOQUnJDCTTIuyA?u-;bH zLvT3ME`iLPa-ys*Jsn&Wy zH9V_<71lRW7f11n#XiVLeEqHRBLMb+vE|b3C`ti)yYLN(}aY>Z2iReKS~uRz=W{lX5)17bhZuM6fEQML}Pu zKSu7(r1&VkeRN|gS=7{F(5^5z`GV)sWVL&}g7NjZBRMRt$W_67<@3e)Q%G|{2e{KX zRjk!;%d>o+>2+UDM@O!SG_oMhxycnWjF%y>KBnK&=xTqod_x*;VO!etlSXL7PF7x2 zxHrf=a`|ct@v@UY5jUS)sZ_XYxm|v=PhA7H5iGGkqz&^WcVV08bu*glhsVdei7-H= z2^tn-o-ja-@cHdOz`{3w+o!D`F6RrU-k_~VE5tF!%Ge!-SR|13M*cdsP~B`*AJ$+0 zLK?R7i~!D2Rb3OG&VvlOs4(G3Qh;I07772PX?*AXvq~=v$SX;Nep#9P6TN_%5NnF&s)~Dl7 zg z7ROH3^OKr`=qcgr$1hEqrRAag)8a(C1{Bd}RSneGIpqFm>C-$CT`QcJe{&?dXn}2+aP^=%JAcksbkjzO~Bv=X($=|aK4sPKbwFmas zT4xI47e@jJR&z@+3k1YEc*xWrA=6`ty3uBCjgy`s3TkMKLN{jjO zQYm_>F2IygX`F5A~8BO^WPcvzSSDw6MMxv!7Y5 zVfd5tW2>6p{5bAtdz5S}R!2k0v+y~oFpwiQ^8rk9)RMx6lG_>1_RCA#e04P~87)!p zc?aLRDXv=Fqq`eQAZybj_EzfyW8-<hsq^F{!{8fm61;m^mB7@(AsYbR~~n;KG9SDBHJdnp$C{;b>ZyBv~%KK{bLmm!TINP6M)tT(wgHQ6N)P zyIts-R=V&Bq(_+#lCfhQlJftQk5=?|Re_ww8Ji8=b(5O^QVHO%+DhrR*kO3RH2edy zM8yN&q4yu9weRb~y!n?GMvx#XHr6w@lvIC|w22_Piz2BMfk|YZO>46yna#xc>|p(d zrk2bXPR^sf4(mPLwD}Z3M}%Bq(er=GKwZZSKE$P{<%-mPV(fL?rjvp3jZyYx@U)le z#2Cp#O^YN!`_qtLubm%O3uLdSH&&A4lNoV`0?wFDequq=aRu4^ci9`E+JEVP=2Ee4(Mznb{E_yGsv5DI9pv$n8s;J;g;?W2p4;>6S>LwlP|k=E+MA2MRLg_ zWhyMNI8L|k7G486$XvM-b9UVr-V2o&- zHh(vnp5ePYi{0HccXxUo(%wEFr?r5==Eqbfw?0FU?B7=Xj@FMI^>2hfQl||@iFa8z zyOm<21Sa>+avVhF=x9S5?gx;kX+KO$>2oOk@lHQGOSW}f+Bj0bI)n0y$Jd(=kmSdw zSq+gjx^Bo`9M9~}_uHUaQ{ZBBL)H$-zpn@PvO6B|`N<-ZqOCfos`m;L_v(A5ql%`Z z=+~ESa-9SN<_CNaC4%cR`kiqcuXm3T(Hc=>Mdg&3;+i?U|adzc)7@ z{zbw~vc*Oe+EI!dz3Ju)lY^=m8R;5j4{tM`_*4!Knxv*~p+D`G(RJ{;&B?{)$F3C5 zmT3}MoECj$O){xH8cdPjEAvyLtv%qe%KAV=oiaL82BlGIxj#Wr|MVBPcIiz);Aorj zqUX}%qymx&Ij_yt=tfR2H z7`FD?-smC5E+AQcSL2nPl7& zy)EePC*to10`Zrj=5)VN7JbW)5{`q@O^=y!bPTkwQP?Zd7E$bI^a3zU!7}HL_=AHUljA>A%_qa?Hy{3r(qwK*ud;& zR(iZ2*9K7MuMNzvRZq#!TQ3Nt(o-q0o@o=8iHpaX)N#yRms=MYG7TI0bUlu#nf@wA z7yB68;lY^HFEEsW0*QNw^B63KjBQ49fIsm+J1mK`ZzXm{e!UPX-phaMt~D&ubWKUJ zciIb?OjW_UBPyov4GM^SR{)RNxuF$&FfrH^d{&7bebGLlFRC9w2nSw8(;}W&B}mtF zm?{Zzh41Owy*~d7jle5_|5tx{dkyWCqRq^*fO9nQ>rA)QG_U^3`xY(2D>&q*T9-Q~ zb-T&@p@Z+_s_J6`Y1ULu`*~Dhq^i7}oIO|GguavC0>a`W(kln^^w4(X>0eVLBfZ}y zuT&r|{9C48c0AL+#-2F-PjUt}Pu2q~-DX$Qq6^`pminZNvCb-X$&o$HshpW(dAl1U z?5g)w71qiyB{uv6V@k0`_rd;bgF|D=3SH*#Go$XbPmio|Zldf)Ti$d=n%eXut0#py zucJID7@+zFLRRI59KZElX@g@5g^9G@J%~!vJpzkyuc&34!F692 zEmU^Y-*YaZ?UKHfXsg1Z8h@~qc*f6Z)N4d=V2k0eo%Vr}VayMOK;mOFB^#{$SJ7QJw#&UG>eLnyxp)k#y;@gh9cw2ldRWfwMDALH1KrNoWD;zFJBb_wTSu zOw1OAWlYPV)rd8{&GS|hf!`V;x! ztkfJH>!_`ec;cxmz);uKcT18=;g6xgwsl6p0A0wt?$(@+w1q*w`>xFTNw8~;g0V~` z!!>*#W*A|)xdg;h0{vk~7r!%aDJceyYx!(XRuo>a`D-qg7JC};yDhNU;8Y5Q`Ui-V zJC}_tLqBqv-#B=$hFmAyZ^>Sq{&nUFSYXQ!+^hCfbvDW!tI`9yvO;1vPcV2cxsq50 z>zn7s_xmf{i4(Jl#65V4FC2M{y&*8`$+t~Kk;T*icmAzcp&hzsE_jY51Ep$Tv|Fn0 z6&jUR{JYb4S%dP0DPq4auFGZ?BM3w2d;S~pon<+iZVTfC2ed$C@94wFgTk|>E@Ruq z&proDOiI3WN=7uHhKP%(G=W`;UCQ}*`@?G8;M7(laa)h2R)g_o90caRf+w5Z%p4-1 zN~(xBJKYDKxuU8#eG8Pfm%{Xb|GfO$_~{hoMs~`3a~eBqO$ZnEmCXmk)KJ)gTxQ&I z&COKWRA=-2SG+-CWbdqNVg{(+_*nPkd|i!wUO`BM z$*sN==69;urN>HYiq|JWYfHiYfs`c(>-4Gi|M1bO$dGs2e||K<88kL7G&WI3iLXuI zn!rg{vz4xA$blCJPikO&=h7;U($M;1kRp7j)G@>Os;sEnY$4O3!_*9;@atnJe_&>+ zU0*ni=R6hOQnoAqi`(;n&SItm(GUAYlJtcUryAn1Mha1)X}@#+S8nS&3x%K1>bPX1lk}a`RX;a~=(>jkR)_ zvWndkhE&GS{C~9o+fWVsCj$*dz+p zHwGn4MwI*Rw{Bjq8a^^Gif^C%9F)GD9@f!3EEy8yx7e*IvJ$eQB8Wd!QJh}xgkpq_ z*xiI^Anx4s-MXuqs$stAS&vm_SpCJ1Usiis)sZy+`>mo?vfMis=Ky|>;bC9k-YV-DUJKII+;;Je87}UC}??R`x1#wrmJa95f);~M$VA|=fg|aD0N**u8!v3s3>ii&V7NS}o=Cw-(YJJ8}bwg)LX?J0*)+usIhCiU7R z6jr%n!N3Z2Hr=W96l$+7VL{w+aM0cJD>@etgM_Ehcv1 zadW&|rlHM$G%IRt91~IS?HLTZ>~CK)Cs!VjSyi9%*zs5Y5_whvK{sU{C||l`a)p_~ zlbP)FKch5Sm8KZa zt{KdNLVF#=?d_2)s*H{3AS8r=eNlSJ(CUw~#UJ~FV7mNYx8=K7n_+NOdy!YbwL&j- zU5Ab2E!INg(7gM$v!v!+9d>8N*|S8KUKfhoci9>vRpx(RKf@^@wCG-v zT5`Jcd)rN%Vx2NWL0cC%cM-;l*2$75O^0_ZQ#=Dt-I?S;QvF_a^s}o5TTvQcpx0+B zQ`sInm*4&S$;$lb;}uuZ8v{6UVMtX8J*-F=cELR=jQW~H2gJo3{l5R+?fts#1T(uw zISRy8O@?1bU9Y~r%}LalW}LEdEJ5rGSJt>y?cF+>*pX0;j^8$zHCifrhSM1QP7F#9RrH6 zQIv%thsE7v3AMkwH1&?CTVjPn?S_h|dAxywhllP8*$x z_J+l6id}MixwiVnrtZlP5#)Ex^z|xkY;E*%5?l208m_WvlKVmMhomi3uE-(oxYla_ z1?)wC_=Jw5SLj(Q569n$_i-AVaQ7LdTwMSA6Ys^#y8ZEw;0PKsM^*oALyn?Ch-~nU z#274JRU{_}b3sM1NFD}{hQ26%4k7ueMiBKK&61^v>%}zz< z^M}I;>;ge|`M070T00uWD9!U5Y)CO5X^?3hze0exHWrEq za5kEh6)OnEwJHdSim5`(I&1&zzqMl%OVORZzOz9%lPbQR+bjz~(;~<8U5D9uWTon} zvT50OcAi%|2^cm3VnZB|* zb zjQr#$_2Nhw6ld>!rI5|O4u;r%G+$?i{Gq5yS}^tKG?A#>r4;%(m3V01i(3RY*DE4e z&2FgQ&Jjq{njka0lRJoE6ZBG7#t8PW%u4fSt~hZ@^|kSal&Y{WKYH&}zN(sQi57XL zE`Wlqpz$M9J~T3_1S*@SNN0Y$P$^L&{3&AM_TQ+mT+^o#JLrjdh3pSQrBNW)SuY7T znIX@U2KrWG-h*HTmVVn&x_~odN~8_Wpzj_T2m|2FPYPx`D}?Y#H;@t|K` zvC7@+7@H>E?>(Em?Rhij*rJqOjzsf)<++;)kuBeI2iFgL4OGm9K<&c}6;1 zQ$c=zmsS|a1|x`ro7Xu%35mi8Hm#mJ&oPk@dT|h(B5?er0n$r4qbh*{`K@MLVdkR8 zaVnfhRwRmN+Zf=BfTqh=_I$JdFlqe&f~l$$bG6^9TgqkT7#*7~puerkUT!ml_d=IO zpuhRg(^b;oy6JWq({ChdE;!C}B9H?;pEE!MKc{^0+3Yg`shWxWO}qAn+NaIIJiM;bx9359>sTTiai@k0FLKayf@D@8$79$Js1Qv#v9!TU-7RjArY z{Dj4g7N>FY()f_~6V<~L z64+)`l@WbqMbFwLI2Ud;w2!H4CPG|n;F^BL(?__c64yPR$*MoL!-*Cca(e5%-Jka>;{vW5OetNVa+A^z zi^}3?U7Izp11({oUbO~*+ zln>imypa?i#dmci+@mUCp=IjSdW8%x>|XdhU%cQl+arWQ>?QY4NNx^3SKc1He50FH7KbaN+;x?snC*E+i|OLz)Try3 zGp(8i+}uoo6&%@TWy~bg^8ftgv-rOMi2JR0eu%WRS#ac*Y)5_%IIy8M;qf#D(!?3BBDBGmj}C_x%x^iHgMVKwJTSL7@Vg{Oc_ilh zOESpN+yJse0^$>>(5y0%Ls##PYA z&WuzF_>(c-J$-F7Vu=alpFuNVw+gD*rnH~SU-v-GU%#dvo>A1;5pp<-TCF3pv`K_( zb%hba;~L!`p!!lRp=JK7>c5#V-)b|nJgl;!BabOk>49~GtH#_rioQO_7UW-o=W=qr zug|Z1qF%@%p~|nMo41D#gSu_Z=7Rp`A?G;?cI}VvFl)3`v{X;+>Ie@4Z6&C?`;^Ks z6n0v1Sb;K{)?rX~5PN;T)w@Z26z|-3&3w#hEY^^8b!V%s@1`dir1eboTZN-S$>rYH z@aFGx4w@K>jNYm^j|?3L!gU}}QYP8ckXp&n=;8A?azxzVck3kV9oj#&#`(4o5s=;H zWIsPC!hAx~@>sK5{k7nJo1Kq1g4+HH{YL`}=eo{cj+YC;2Xh@?ykXGZd@W4cf~`EW z`=3fXW6cs>a`%+qVu2=Lg=SL|p zhZ{k8Bjn!_2S{Sge*PyIbSaUeca8gVBg1!}&>`R5s_Yg@V8J%QC2trFa16c?rsauR z>!!)eOu(z*`N{d9QL*1Uk>DF$OMuJvW~j*FgE9lV{t8byE8>?~IGk7IV5QCZ9vy_% zW_s?F?^0~z@};ciU6EDZRZ}P-ecf|)+H2q~eeTVvF_~( zs!G6%Ud}wbYLYd*d{ZFIP_tLG_i1mAwrV!0Q9Dun31qoTRw>HZ(cG^1+y3i1sUDE+ zhhJ-%obN)74PV^%cBE$Ww_VRlpiM{qI=zLQa=n)EADElGo4d>@tTq}#=8SdfJF(rd zSQ2!#?7hV3rlE%T)LlFciLoIK35Oy1yIkL;Uh{@O`4F1h^_S`+s#l3m4b$>4)9^yCC_&)5lEj;s-)%Q5A6dNrb@G>p!L5I^P1sLB;P}KTCz?tg}~7{ zY50#&&Gzfrc2_j7eg%1bK0g<21$_F1e;JIFmJ>h%2M%Y$dZmc0htr+2K;Uz@WQlwx zi@s=`(pEzmo>~ex&ztP7R_I=rEyKzF>12$2wsvyusMwYwUxZAAMRK}N63489iVAT- zcggfL(|$7>0t%xEO{598H|-=)Ktglvu5I;M3L(3QH-^Kqiio%6qN~{JGrEdtDVOwx zPg5HAP3coOF?@{Wt7{U6Ek8P^OgCE;mz!MblvpSmd`wrJZ#5{fThn#Z1AKQB+qv5F zm%g0yGAeePv!jNfr5uJmc~}iTKnlT|w6Q-Zt}FO2>Vw<>o4>z%K)GCOxNe~xDA^Sv zDvpq6!F%Mh|MV5k!^cuP`Z}-_`(xZ3!=L_J#znt5hW3D@hDqpnnex>8`c-UMXDgyKJ!;RiVf0*vtOi+gNH!laElI;1SIp8^J~4*PwVoQ{1ePftI)Kfa|2R zGco-ssmY=$8!it;8qQJW`tcKSwC8(x(w=O>Ym?7%tCi<)DvkS8rdRl$DwUqmrzng( zT$4jEvu=VxF30+Hn~-f^VlpF(h|I8>XBcM3w8clr*X^MkC~7`A8zuWMh zazvK7R8i$E@d%-%O_Sek-H~MTI4Z?!jKRa4!k_uAoRY;wDGhi$Otxsp^RRyH5$z9R zn0^Dc1-0>ZI1umA+?fSR?!1ZF`M_p~>ECTl{;HkR-Wn<@DLcG2)=Hn?DwD9!`e6H$ zL;kycNgj)fhFW607ot!fo!+xNjJJZKhSWN*<&SY+g;N(Y zJV7I8H9bGkQJ1m?o<@83wkpz($|S1k4?FlMp}%IwaUl4)60l24#E)g`_j_kK*^n{k zA?dg%wCSp;{vZdrnZ!%4AKx01ml#%NZEidF3({!Ih@CGvl{omThYI;DZ>96vDDZDP>K#we>BI2HN5Q4JAreTnv1PV_ zE5~oWcb--Vd(GJucfWdyB@G#WBWO48qSr-nqB8#~^KntWfL2SXZ{~mQpWT--8vfKK z-#kW6Be6n-2L^pEH@39us$3tr31D$Dg!|MWfOzPy?8YSYkP0Mi!l3865n{S8e@LJq z*Ot_>HuB$f{dSsVs^Ppx(NJ7+#q@zEjP)g;6qjY>0CZyJg! zD5tARJJ(3&u^HpnI7Lz--zMQ|RN4g*0#wl1c@ut*Yc)kiMMc@cyupt@U&dDWzV9BT zrMROQIv6gY%2lcD&W<8)3MefqC@M;_x*GVqU6Mm^@Y;JRW`S&Tvg4!0fGfHSS*sP_ zcu?@seS$=M?RhOfLV%J&?5Zb&SXv~sqt8DpjWCU#iQp>iCg6CM7{0i#p(9E)+THmS z@>DBjuj#8D2*Zlx@9o+5;voI2J}ZqY3aX?14?V~qg&)6EupWLQiEW!j7B<#f)~HDm z726!UF5|1>JN$OQlbtj7a`pP9K#S(D~D%K0Y~P_8+{ObK3Ed>&#!J_`)Wo0hp}NdaQ3`tIVHVH7?yrn>h1*|8N(yD`3hT3sa1OH6xKzJd za9naYS>5ojWpHM&+qV_j?_|@oKe<`?#G=iRASQ7RB8Hd=g8O!ribkLzZ!wG=KQdAl zZZ&UJ=xoXLusG4IJxw?b`N6NbnED%Tmd1HtDEOBVauz-D;Uw8qBxY%Uu=zw~fIuA| zQ_8P@rk@m|z@xY){0ju5e4n*^>ije*@x_Tie#IxDuxE{^`?}@H3T#L76W-h9Vo#B) zU{oMRjQEl0n&|OC?#b_QvT(h29a-U+pt`#^W?m5Rp0uZBz@^x*Kii8)-Ix=?i~0C{4SVS{1Aua+h) z{waveBC==5xMTIh>*3x8^$)A(5>-3hHyry&Uwt39?ujmF7n)TL?5u6P96GB0D}3^e zzkc<<#|0$Q*&QQ#QhF6hmB8%>_xnQ=&-SM4J*wXiYw2z+i@vH0ujM`cEq()&CJ`&h zw?9^dmFBSIh$4#ft;TtOK5|)=?XG0kh!ME-QIF#c1 zxaW$=C+ZVR_|l&THxx73U@Wi&uj{s?kF%(T)c^mf52vnbFzp=(bu6EjK)%X$Gl8;3 zibXSJIrje=o|w5Y(|5co4A%F!c?vN$@ncV#ns1Ggn|N8Ql>!y=^$FA!xQBqvLmU6? zZkUz**pY0Vvd|*CsQAE0Fef!X=JMxON{*7pgLbrk15IIj%ahRM`z%X(Mg~Lq_cQS= z)Kw~__8D)6r)T1^#h-+5AV=8k+zf!ESKm2-EaYo17bUAIQb>pC941!Z<7Vr5>wpTQ z&?uHxm5z{9=`TOoclV7>^V94)DFkqpvr9XnzLTYsxq_;9O2q;a>fp0DeCT^zy`8J( z{-~nJs8J4n{2uk3Zc_zRTkYwIgQ!`d%}orMy_sXu&8u@DO2B(YelR|*muA{M+kHdK zNma4@f`G+nsoCWnOG@qD(sJiQ#J_UX#p$JTc3%ZS5PJK+*-=s&2EhajNG}lufi^k} z`{RtpVUg(FK6O@CR3_q0)@4ta0iTu=wpIwx99losD*2 zKwoQ{uhujtI_wiFwU|Y><;b|7CGd=w_ zP<5)`;QgyyiN$ddkp^p&xwn}l9PFQ}O`(M)c+-X^n&M6CBqqiLp)=dCu$|8eB~^*9V1!}rA6-QUs>q1K~Kj~}=4llmLDwyZ4fKG{%n6-oL( z`{~$x`LKH>^Y~dCSkbm(tkLQml*p{ ztjW=0p`cdc=e?P=4bc+oTzgHs`}dmcwCt)z?yBRA72ITur=pVTcIq?H<=t6P^4^Js zG|Z4Ie*5F={LK!>w=gUmkfB^ZTzMKIuzW_Br_Vw^HP9;rzhsks9!NsV;QnJyzLiGS zBudEVeCNYicNjPjRmqwoC{TzSg4T#3NStdj=!NeO+LRc|94}XL<6f>78*mB-bec*P z>3Z3@*_yQ>S__(~d;@(ct!8GzJGc|09}GGT^flNOn0YT|udyA&cKXxpg3>k-bGYVY{iz-tZup*^Tpn{807s*9sy-gs|H2{TGC=?0#%kyP1T7RHUl(_ zZ+MyW$1CJGA6z=fj8U(~K$pCwEGhdV(L zS3*B|(kiLymIu`@>`<}J>xEQker~gC`*3Q|V{2$0v}0tZ+5T$eWCa z&%_fi+Sv2x@WVcDalL_gV-c|AOTU{Shy2C1dk4hNW+_Zms9YG4oG6DYl}XD?>;0E3 zgY3{jNvSj$5B-Y%+SdWQcYHV$q%%gleq6gcSDr@kD-mSKm(~^-wzTG) z)5h^xgs3EIdKLi$LTM{6EeXYM(@zSS0>k!n88&;o5OKn9EI?3TTd^ zB3}M`eJvLi#DU^VDR_M{>aDyYmNyz<*qPF=96^m}Uw@qwHEHBfv=kn~B6^6amA$Oz ztISS-7>kherBR@fd=As;sZe^D4A3Z0wtPk3F^0+j9e|#eK|<_R4vDA9mFx*LqH7K1 zfaas-PgJx50eCuo5K$<<-9PvejsgmoGVDG;ATf=_VAYx5rEZL$PM`zNZnq_0!Whb! zpo5Rd9ebi1k)wurf3GQbr7AVOD2uH`aDr~>hW9Nw?6VUAL)zBkP1sbQYt8p)I|X^s z+W*i}$any{GahdS8-r%>Y%BD}Q;Q>21OK^{9J}RoVvLZ^rql^e_34sYMAgf0S2JMG z!8*8jo&enRN&?L27QAr7{|H&6gxPH7jW$P&K{R9#DdOQQ8R%m&Oq8z3{^UX6k*sWy zpoAh7#!hacv?2(kge(5mZx=DHB$AODrY=^il3*4oFJa>|pBpu!OYDOSuZ3rq-2-pV&mwLxn~io45*&xgO- znfmlSkdyt=%299TG3}*fq^DR}IiOD6ID!M|diqb^5UM(R^CdCI8gi|#eSa3_5yREU z7r6IK4-qysf>q~kG9R1xnMp_6@ajGc4}y!2uTet@gnFo=9O-Mdp)&zISvJShuJ2Zu zx-eRLx20Bon@%A*qMA~CFKhV1w{ZL9LxNOc^n_gFvM1Y z^!1Yt*ln3K%(RcVJSjx9($B|JnL^We9%{pCpNNNm8eMyv;JRpPCpu$e!?UjL1X6it zfYl55g0}wLtsDyL=4nLe_SBb`rpEc)e{C6iHAzOmBGn}M#USJ2T1Z|T1b32tU2AeW zeP7{_`u5+R13I{)uVb1Lf?iYePi*PJpJ-qVMzl0>N<~IUleSEu+4MA~Y#?L0n9NM) ze`F+-R4-p~0Nw&K2sU6t!iD^@)MR!ydb=E6WBik0{x3`wqE_n}`gWQq4IH};yi2(C z$+mI=fB@=+o5v|6fR-Abl#z#lpDC>fh9aj0KS>sBiFFIQ(8;x16LKLtJvm_x{Q#f;&*L z0KQFVBGbm7T}Ovb_JQGV>j|tv_pgTN+Bpr?pHVNYOK{3%yVQ+1+*q-K>j}X1kRP81 zHybc%HAHy1vQRdLGP^gddNBGCTpA$>p|EJrU2SAo0 z(X}R#@|pllq$9w31Sr(Y?ZFb@;5z@?F@AJZ(4>am<^9@DQo%o83tCp_E-xEFmB3WN z)@RCt@+i=7UO1C1T~zR0sz?KX?LyW7;ORg0u7}e%`N2@XSq&des+7Z7wOx$oE>g*s z3WGLPy}K=POMRF*O2PZrS2`Ac=anTu)(lXX_4IB8$oX&01YkWCq2&JzgIx-6!>yq) zZUR0LNDy$&}>K%@2d^#SG!Ob9?vlmWULYNT!S1$t*pfV{K-baN!f#J6Hfbcw>H z$w5BrI6)p7A6+hb^FjI%g=^ia2GboPS;lJy_|;{%3aR8dcpM zXCH&}74Tr$jz3@eo0U6LnJDD{tFL38skPPQvQ!= zn&x%2D{A#;;Drt4rIYG8xg_iGOS>@O6#gIcAmHBu7QnBMt~zFM0l)~v$Hy;?lfly9C<5Uu ze;-~UC58VapW}_Fh-CQ*rA+m4nM=Qnbl_<~qo>}b0(Sz=O+YaGERb0PoJLHjB>rtU zJag}E@x^^`Rs2ifj9>sTK>&pY>aTqOd;D}&KyvaRv)jDCrW*S)`@xfgQXrJb zj9bz1ae{EsO+Hi8A72kbnb73pfuemz6wUATM;CGh_{u<)L;;gT;qlS7>OVsT5X1f| z06;(3I4pef@7pd?rKJYVVQ~EF2}2`*tc~Tp1yK7Af6E9qczh?W=`?6BE@`AwykD<~ zJ)DD^<|ceBhvedfd}{>Gj=^0rfLU7V?OR1f#dr!KDNi;krdu;FD`Tr+B9x?GlNgNk z)Y3>9x?Vv)eJ5y1AS5TZxQmbzuO2z}e+Rx=+eygUtVwW@@MoN4m;Xc$ddtd)XNl7O z%0xcF5s+XCFp{%#;Ql5viKomQ)r$+JF##aZ19~ukCb@HL;l>%O;^V)^4x@kn9vAEx z%eALH{~56M`RnR6=%1}Fvr+`d8(u+L-nbjd2X+SGjiyj{axs(V6> zzO?8PUu#MV31~XjBp@eHSm(wCwcS<#xL=9k6wp1)&u^S>+8z$~zb+)&o*9`DpGkfi z`k9*G1;$H9detANyStMPmb~CL3UFJ`EWl0R0R#(93$;<;RolbNZc;rD#$il&&Ah2C zxtPc|PCJU~f+#>@57_i;BRfnTR@+(|(w9ON3<&25g{p)K-z^oBP#+`>Zm4>T(etCo zJ{75VE2euH3M{{uKH%#D_^|-w8ep+%f@16*s@RX0sM`kq2ETE*q!!XV#9@DoK#j)! z#JA+97Vp6%j{~AkBvXJt4cI$CSmae@d>aGesf=kbr_>7{&%cDQo||$)o!VT&#u%#mQmt(!Bt&S>;2G*

#S;)Q~Y-qU@^!PaLmle z@CEeea0{61U4oB>;_3J>DW;(}Iklr=bIv=v7l(EC0Dc? z$E^Zw0vwJ;Oz5c8UGzzP)l><@VaI>|$lKv*MLz9$;`q!;7mSTKso${9ffT}KPzN}k zG$~aMl5hR9V(lV;(y}%2^=oX{Yh7U@uqU`Rz0G8gvLU$iSPu2Cw*?gs`s9EH;Qjme zDk|7wI+yIq%)^11igw*#?fGOGQl~vj`6`m9*2ktkn4OI}*MqhG_>odv@apR}V~&zV zG0Iy$Q*hvq?J#9CX`}c@k!hr_@L-#_RQ7g*)L9@%K=3yf^>Ab3-PSzJhWF5tiHb#$ zwsPC_z!3}L)_B+NtQzEav!6xa4EYMIl78gmznN%OmAJ13OA3&q0h%Rfmf+cZSovIv z3$#?<8;_h-q1}Lq9Mua4`?`a}re>{Yj}`YC2?mnF^8*hqF+~UQ-&37v z!JE?*APZy)_=+)6EC4m~^)+ZGImunG@44peJN_q5WIa`DmO3UT^dRFjqW$_w{G5>-fISYb0nUoC?Z5 z9MK5~*$R+DAWyN;HWpkFc)58X6HgA@iJx(ltS```re8AY{DptzYWqAj=OL{Lj6vU+ zZiC*L{-k1KHWKDUbSCJi?n>apAb^kPw)!D5GUfrV7+?ug_GCj~%DQ2?dc5CzBhU4m z^sCq8f^V2F-(3L4YmD}`pv-90e=UvcfHWI0)js(FU}LSSg}3u*uA3)QjVU#Op93oxX~XzR3_M;p zziIYUJ^iz8OKw^g?t=;XY$ySFQv(3I2J{%tbKgI}NkFeQb*3p9FY1Hv_c}beqmC1( z2p9`ECRF*JT7%yJmm9Dd9-w{(qd9vAYbWjnh669xSe(7L9_sp}_e-cm-ogjaoawPQ z#SE0>D_p>{VE=eHFsW*^&@gvn;fybpeC^RyVjXAgN$Dt1P3pv10JM_l1R(2(iH*HH zSOiquWt#?!6pF79Yn<)R)uZiu4{kMAo8sy+=M=I!NO*vR_Rr3yrHcY;A*IHaRC;y3 z!ixuEiq&Y`X{nzPR~HvrPW4#d&vzywci}r0AbY9>hoSfPKDFs9qV6g%S{M{WuMOGS>We(&Y)E7E0 zI@;D}vSZS|8+3*LWTid_;?xCP%SnKAeRmgNPT&>}cH(<;4ds&h3uw{{&TFQ}Vb zF+A;GS5QJ+92-BpeFDSo{SM~A7wntr`ucXTieT#iglqwT;#&)Fr%R7H==l+fCNWm6)S{$D zg&9;To1=)F2{|Up%}Qn%w^d8+XWHkFd3iCOdFFS1f4`aM`&FyBKtb(Fq_JpOc%^&}UUQ~HZwus4yD!-VuqD%(8 z+Z1`qF_ncvFoF2DV?!2SPhYL|&5Ji9Rv+$H-4&mYwGd~0$E^i|iK!{bUv`)QoQ^oy zour;W(;rWp?GD-Pe89OO_cq^HnaGfmQFFWvHb!VdgIM`GH`f|)g|O1ATw?O4*1O{y zXyHqU3@>37ew`g%tE^m#wC!q7|I7>H?abmH$CfA6Iq7k?*DynrGq9ie`vo(J@~al6W%N9SEwt5&ifth9(k=E&aGnOHim8oWzQv@s>d&w5CtbTCeWAMw^^%?YO>c^F7=6V=281 zErugRh5G)=IA2JuuC5=TNMcNpQl`)$R4X7x3`PvM6?7N$` zPC+B>eWRoGgQrabc+)(tR{DO8RRDIn8X6j)#A2<$DUP{B?Zfa1qyoqB#x$K(%NBv% zFr!e?41bx3l~q)I_z{L#?`WI)aiZgY#4K$W+SAUQvh?&m8JNc0M1;eG;Y zXxla@3nl*wilb@cC|o4M)&MNoQ~Di&ZcG(ANJeI6Dby=CdB_Rxbp8^WLM4n_cpFt! zkQnLUMn%SlGw*a41xSkEjK>;MUG41`i9l=_X?ujNtdGxzfu}*M+XW^rt`eE!nb}?F z_Yg2NXJc|^eBjguLnUR7xk0-FqKd*Kgx>QXs1g!5IXNT3no%Nq)+pcovqqLG&X$j> zloMY(ljeNjfIuLydEp#JX#2X+z#u7j{||R1wymV31W0ei$@F)QC705h5aFU=gBQTW zfVL^5h4Wh3_V+An2PYxp8XFppe9YgqB?*fGAzgO5kgTEc89H3W^S=iN!R~E-_ysz- zTaSG%sWt2tg4pk{KK?#^4mx6Saj26McWGzM>(_^Yxxfd>ui8Pxb{X;hF-U3X`T0sA z^K<@ae?H#cG1sDNkI0SUTh{ej8YOxp68qspwF4_96Eu4seyU}z)0GhiD12@<=FAc4dRif9Hos7RqgGV=~Jl=|*uI6B%1*37uL2YXNC zX6iGL(caCCFkuWjraMu7Xp_2nabe-2NQh039*rSZD4+>2hpWofvK=y!ryef6$SX+4 zIy!q2biAV7#;&Iob$>#{Y`Cr=sONkT@}uL4a=_E3njrxrIgj zZ4(1^;c;BhSvZqM2CVo00p@SB(gc)dU;F{PBTFI?T92T@)RgXuzC!h8?oNSozdCpuEt>cZK7H^N!zu&&yO-|qi>>hSBHWmu41Wv+ml? z2PhPYWy`?)tw4i-o}N3=8d6-;ok81T7BcO*V@ITmw(~Q+SxdM-Qc_ZASSPxQX3(^G z%Pjx>OtE!--s_0H7ei{u0Dv{XRx^R~&1I+{h!Q-)lH8Whj@o>~)Hm@m%}+4Qq18Xg z%mmtCKqja1{CH4>;DiY$oOpshljou*x{~t|XM8REk4rEngi|4bz~l3aPY>?ILT4#f zBv@jj(+tn_I>cv<_`cWG6npdBv#B3GQW&KaeHu0Ltv^mTCeZFn>n1XptfP|)atJyY zGQO*QL@fwS<&hr;Vx0G14YE9ewVZ&a_P-+%iv5N4>vfXqO26{5p&_C#Ba)MplvKK^ zo>UjHFw+JA4YLZY9^nv-rVMUlq&*L)xfAUSfI~oVny2>hJ6`zpQGtOwYN|G*K&Hn9 zt_@eItb{QHzYC^COG^ukYub>!cXO^-D3-_L* ztduEXhI)FqDg1JDG;E_MSOitDUcGvC^XHr!kJ$Zo`+XhM5-%|rfOs1_I@~o@g^$O_ z?7D3l`u@WQ*GeOCVgQ>zl=tLGb9Xm|L`s<3MkJP%m0f5YI!V$qZf;S3?f8n_DQ1i- zC2Xit_wu=M1BBvba9N8N%XoklMtc#ovK_83{#C{C_}Q0H4u#A8G!3X{cg*)@EvUSF zD0yWyiH^Rk?>;;7VWqtMgQkO@8+*GSQ)1)drY4a4iYc~+96SzxE$fOX@ukI^Ln4n6 zby`_j!3joXXei~^@V^~h0D^k1XT#R6F@F<<$j3_Qi*F$a;6CQen z{v#kOS;1LH9!tm!{3R%m6C9$tq%j1h$qoe1iKQ|%vu?L0}9aVO) zqPp6^=i@4o{(%8#aW_*_a||7)4tq?XKMY~U0x4`tCVMGC3JnMh6ceG`fjZVWgp_S{ zgQ(NC`EfRfv$0C`#Na{`ZiivWG#f~XT}8{0j5R0GXa0ncdgYQV-J zllAsBK5Y-X5ILRvs}s8)Xg;PazV_}cG1jNK8EK`u5+G|pon#*^m0Arw)J@+!TBiAT z^l_P!*BerP9(vkHad`IJr(-trPB?-Ku$2zp6U*aMQ?>_>AFOm6WZ=cH|Cc?p{__T2 z)vv@+_7}y4LlMJTJS705OdUDEc77B87rfYSoW3hGX4(;$CnDCpDMHFVxT*u6!Qie>jK zTC_;rCe;%@W_@-a`4mHD?{Y22mryS|viIr2S`oW==;%?Xx7q!F!@TqG@aWGkEsX#; zHDL_M>Qk6cR9u`STdBUbmdMQ!CmyL0UOnE6ZSq#4kx@!}f}`dQj^PI`*NHS^Vr1k> zn(27``q#XjDWVMn7{<85r(62GaBDlo2L1>x`PdI*bQnLySf*CT%TPI3$!JB)PgG-T z4g?b>&Zb;<1FpKR>yu4}h6SJnvCD$@_yI9w>?|U6cv+x_>KhvyTUru5;je{__x?hs zZ=4tuP8X&jt7K(ah5tm!P>Yr5=TQ7Xu7K4 z$d3aOO^51l4bv`!w*f(K*uQCl<_bF^O0!Qxbw=sp&0w%zueETKA{r-JNS0cP z2mhilL<3f6px)mo%D#aBQIvgGev2qg$aqPy5}`RBs$=ATnkMlw3e=)hS`6p>Gr#G_eD&(&>b*O> zV{a&|HR2&~v4yS6@i1MI0Hwl~sO~%LLs_lfGK8mIxF6~3jvu=UT-tSC9)2&-*viEi#afs(5 zKTe|KAwoY@${pl7a$K#ghUl7p@G?92nqe}X(G$*$cE;0LydKqz63-*>5-$rB1c&&m zoW8ELywVgu9<@qU3MyrqS|T3=9+az$7aK;4CnUCs*KtJa9A)1t6Er8`hMfJr@ak#>i_-J3UE3LX?7?2o{ z7&w6e2qXrCVgUAl0gpQc+#Lh}&>Y?n@UD~rP;(CB6}EFWj*|c<=c=M>pmYOFPY1vT zE!~lbU6D~WW{={PA;iVDq#SR`y~iu!W95B9m|95Wi9jCf7p6p>AmkZ6B*Z-K`7n2v z4&#oz_7#%IlgN7k$XgIUe)!>MMjqB)5_uw$eG+*Bk!SXi?BhSp1AFs42m~biu9kW) z338JOvUFWSjyL3f`9m2mC(56bWf=Y?Atzv72U#e|RHi7%Sv^1w^1q`6_wQ&K{2>Q{ zgxu!XYrrPnR~bF905}~OHxi!?n|NEgQT4B zdvvy>oH)ukeNfKePdT_pIZFWL3`seeu>8^}Cli*!AZJR*iG!Tm$IdK+|IRG9w-m(@ zurupgA!o{|oP=DPr6;2xUvhc#&xk~lb0Susn3^LwCyH}kADrXA;u7pFx#WIhu0xe1 z=OpK@opbS$O3(=a9n>Z0`U2gr3>g7R0>-%?Nrdb6RCj*X2DI5F<48JKq%A$oHe7gT z7#aW|?+9Ml=>ri!%IzY{_pgh() zJk~mX2v6mNdJ1FE$AH!38^*5d!dqZ$16j}SxeEy6O5JMXylv%W7=Nx|>^6qt`7m}G zC4g@j_p!H~YZwD~7{vTdA3f>LYtsw!rbRoXj70s!AzMi zQ=043S5lz33sg<7lmc~)0@Zy7hM~Ep?q$hMHlVS2=5C%mLCteb`!3&mXyu+A*w(X1 zq5Al{R3_fa)Yu)RJYAzaxqZl!0o)?xYjRen(vfa>xj312{?TzwsZCOwn){-ZrfZZY zuZO8!hN!GNa2`2rJ-NlmiB0eT%=UqKS2A+SSC!^Z?HsYHt-kqIij{yVUVZPBYITKb z1@#`1QO~(vs5MU4nFXcL_*$--X{f|NEWu zefQ3txpQa!uQP7gFMI7(&w76GyuorZq9{lNNH8!kDB@y}k1#M#G+o4EO5!sfo1c2QAUehsy7v0_NOEX82wFj`X^J z>`9?PL5R!p3S?wtuqhR zpp&cJqk`9osA&x^oA1b=xhee35;(fG)2P$z1-8 zYNVZuRKA#D_GUZYj4t83XrjWCz{jymg>lNxGijT!k1qRalE zWYNn2B^9NRP-NL0kE__B2ltEC5wB`Eycg(I0rZkR#)U~!AwM=7+4o41mx3eI(EJzMnm;^UOojhN%p69(EdfhN7 zIypJs-Ru7>3$9Lt?23YFN4f;vI)eCKTuLzgA+EXfph{d)y?=64aguq$H){v}gRb*Lk;d*!1bCq{qw^NJjX!mz(sWn#Y zQ;HhCur?c8CkLKaErI17k0a0hEt8I(VYMr;HE40a^ROC`4OXxD+N7aPJqzyYFz~1a zcioED!ESBEx_HBg)T%tDKkLM}N&Co@86F)1c9N;u`_Q?qF!B@jr}>im#+i2|Uefs|k#RhQ zP_Kt36)O5v37JG(?75N_EmHmH));x*WEn5l=OfqOnj$10ee9kYjnzM-6_@O?F3 zuP1OHR52|Lw}!i>*Ta<_K8`3ReSv+6Rkv7}n&siY`9*$2YfL1lK8J&RGD%H6K~4Rc za3PQVY3bk51?uZG;g>DW_s-7uUJp#{jzxG*Xs&@?7)=gIIKpIk&)-uR4JZupEjh%b zG;42@)*L*z)|6E3W&CE4;8?mob8hGD;vXr98(9j2Yg@W!+jGZ;!f_^?Zi~v(kqKN| zoc3WVA!J)}M&>dbI^Q#~vth;_%+owi7{4^cKKl*Z>NNa`hdK^<>Hc84XK|~AYvtXl zDRR>NF~hCvO?K77dw-)C_KECIFsD_@yyG*POmFJVXA$Ku47gggRZ9t$54ZM`kj!IH z*GC1cdaBE-38x+C5?c67-{`1)wpkzh)p&5Y)!9SMkP!1cmCF0&#m0@sbv!RVm>vE3 z%WOxaw+~wt0|z)dbre#`r^90k=v+Sf?if0!30%{j5PN2G1|vxL71*ycvenI#)#grn z)^2)z-&&X7I$4nL%-nz-dNSGhrf|>P(Eh}&EIE3Y+<$;|;`$Q|4PSi*D<1X&t)*Ws zVZD}JQ_BxbpScztmYPas)dGiCNoN)HcQ;k{zR9rjjoR}Lbodv{+S}BTGO4&34wj)g zVWAr7kAg)!@0Hb#RF+LRz>KRt%&5qh zv`lvWGMG&YRlF#+d^|an1ajXr+g(M+=N_Q$rQQu~2(CO_KHJxu}t$)YkP%cQjR%X1*#ZuEwzoKD5p@qV&Hi=SF)&7k+&^&^r8kFgz-` zATBS0$fqvm?0QJy-t%{>N-&Q)X)yaTzuuPXz=Q||1~?qmW@aJ}-E8f9X)#Zl+wyz7 z(J;<_mocvo2uKvqadKY!7k#s2qhz{lucDju_wA(aDHSw*=xfu*Uw+^#d@5GTpZ zkm(I8N_GqwneqOR8$%L*dU3YVA3FY$frp&GBXicBZkFCvX*?HzNl9XL?EEskNl;Tw zdRfxcb5qk4cl&d4C;tt?R675INqfo+%i4pnPZqZ+^eAq%t!x8FqLP z+5R^L^Kown&5iwFBSv;4hTf0aG2VawM?O{+<4PvHSvWUyULXteBw?cjNtHA5p9%IO zImx?;*Z+(3`rAyT(P29(TPTf@j)g^G?6q74=efA21KVTTb)^44%((yibpBpv47Rdw z2ZmHS@I8c}wM=%W)$=ivzjwYsUszZe1J~$iV`C%htfA{|-lz41Bla>rBHujpA>Z)5`PcK_4fs9@@h4-rIVsT7P z4nq9+4I~P}!or%5*Y`uG-N_=28mprG{80-P`|)HQeKx*#^z>z zDk`Ik{e_EzrHiAZnKFG*kU&C1CAGCv^78WJaw;pw2L>3ZsYR8^rppcc7Mt9cT(^>K z*E*lU!^j5RZOiR(v*(S3ghaM%YRcEIpY-)BT#i;#y{^TTbqBw5L7`AE?wgfBQbx_%Va>?$ z>m{$7z3s7_gT*Eu)6vXl$T+zXw_v3vCnt}Orl+UpYi)ltrD8z?g8bAzcg?G28rVa{ zPP<6GUl6kYxjx&4hldwjDJW@9jEW+o7jQXj9UNq&qw8yHTP2$o7cZB8`bLuQaT|2Mgo%5r4{ACnu-AxVK;(@tHpP6ef<6 zzy?7wk~pl@)zn~f3k(0u)mR%EW`%U4prAb5p2(7uldJW`#Khp>;9z586JM0kMn!n; zlYb2SxW=F1@83}|#7~zbL&Lzp=XUygp~2a|hL)CAzbnF0mYZT!Sg*`wIPF8*F&Km4 z##FJEy`v*`FhD!qy}dgZOWp{}J3HJCzlYlc(cn12Ydo{Qp977XSo229{k1um+v)*C*aHZYe-ae94V1IX) zE-B~h(aA}J-G+p;G|GB$p>=UrwFp0$O`$;4o+(~1<>Pq@8fUgIO;gW}Ao7@ku0tt& zo}Qi{($QXlPVdcD35v|uSTFsVsc=94Gc)KF>>y)cu-^I^4jj3Byu4I0-)ZR3o9GegEF4rKQC}3Cy3W>h$qOUy}KWz{AzhXqF@c14B{)ljUqB2%x0+_(HV` zDq7mS4w5;nt1x^P5Mf{AsQLIfI5;kHQoY>HCRCJaL^7+!?To_ZF6XRUo;`b}RcoU= zo-3b_kRTNB;_7TlClHPFz5`e11u1`{mi$RS!AG>J6tywRj?T^$KKJuq!I&`Gt{X91 zsowW{HA~9ok-QZF;~zLHM8c=YBk-6rnw!1AfKyUZV0iiXmb@Q4g@oGAbA-r7F$$E6 zq8N}}p<>Q?7jC~=TU&#If^c;_&|5>_HeU|%92|ZpAR`-<*%=7(ez;lc>+ACmyKF;# ztEi$RuP0?9S|w4IiGu1cijGMy|?yI(-@?RL1(ejsxnBX-)Z>3oAgD zCa>;@lODItgFp7q=k=8bc_bdQHjNo?4VDiy1=*E(R{mffG+Yfx%eJj`@$YH&rHa|7 z|3oItjSTzLa@mwAYwwLyYKFo3)RB^%(@e@(SN{yi6m=4sQ!CaS$KW)dU5Ig8}WDP40Un7PeQv&u^N&{+eJSJTteiI5=+D3P}& zc}=D!Chw&gqDGU7SaMSxevV+Qjt&Ng2Icle89}J2bDG>QHn+Bhk~m~_bb7Yg!RE{> zC@>!;=GPeiw*dR$wHD1aT(!~YhBlx4)u9Mt&3+YK z7^;OtP2>IbE;lPqeNr*sxp)Q1jHrW+&E@YOk;R&I$Je_hbhjEd8@(~>>+6HzMM?SJ zK5aTt^mn9r*;M{IpIRYYiceVg_eQnF|7D2y@B&sp%U>4l*XCMouE-H_|I$LS7o!wm?=4vam5$gC$EDsU!rDk@5wLrb290{`sQlv=4+7iDX zlw^%r{-n*p(GMS%u3TsdqD3m{qCj^=ZRuY+(lPLo%CCea`68eVCbAV&=qdOQiT zcCjGdC zbakEadh|IFawh7VoKn{JfA2MuK+*ijF>FBhm>UICbIF72SD;j8oRY4(Nn)sxo%M3#+OX~@AbxW%QVzArVxX>~%T-i#6LO=IQ{rZ(_CO`%6>e}585rJP%wP>;= zlt~padxL~5ui%?Y6Q7{l`GSIqeNtS?uSGygS|cdOR6*-KvWkuggSO{~owU`RP-To@ z2S=$7_CIU#mKbf${KfnV>0jVKfl*V7XGeMVY}9T=-^NZ*0x1B+-GEM1l!%9FVdvQJ z@=~nkquJpnBEDJGnFX!c@+86tqR*ko09K&L%4#-+d?%9n9@HlId-q2*&fwtXz5DcB z&CAHqY==0TGhxEP!q;ROsLUo`K}4YIm95T3VZ0zIRCQSsSyT2!pqr6MQN0y2Ofa8X z-kH5rcF9gCpbJ3lSZR-ELk>jM?Z*R+5j{4h6?aJ<#41V#rPpqpo}ZuZ?KO*@4+|Hg z2nh`(1Tf{0LKrHhsIG3Nt1C~%p|1dbGBs6GR#w*0Atff}vsr!*&|O+uT1cS%JEZV# z%wPzQ^F9%)$=A=Hf0pXD52o-n7!Q#c8ykb;omsyV#7=iUtpz2$$Hjs(2?(WNYp5i=H0Fl@=&`f2gCuG_*R`O8g)50067tEspw_7shVsUn zot@@Q6eBJc4Va%IOMP5_|L_ebCmKc(A>UIa6>0`FWFZe;m|tD`Gv&%1W10%w;rP&8 zEj>LwknP{Gu&}&)C(}DL4P!j`{R-e@L)_z}goJ^3W^#F}PAX>Rk)@@j@o|T_YReqi zR2gY$273C!yu9G3q-c2)$RYq60Ff)HtM42f2)G`vfBW{$y7_8zf1yDkM@Fmk)90Pi zt^Nc|e0*1czDT_;SK9oMVf@x&+ZHO5CYMTeh19{^o0-YW%lEYBWjZf;a?sK3g7iAr z-Q5k~H#BLM+i_>SBNP|(6TlFVJYXRrBE3s@Rtxox;6$aOqRL=YQ9 z^?oxISsR#CX^liYPHD2FVMH_eE{Wz6Iomtm5w_69iAnTHY!8=zibj$UzcWDe0eH8e zp#fQ6f&xRU$!+3(WrbQdpPri9c=cB>NXysP*Hu+j09*k8&;+jk4qQtULa8x=t>$ZW zEiF;f%FD~04;DGB7c0xlF&5AF=2U7mKkA0aoKFr8T3sD)@bmM-!M`x6ucigL0Zg%O zqzok&H#Z57lhk?5&E+K)78c^3fuZ5^4K+2jv21C~-p8)u-~f=Gnwt7BD*1L}W8=9> zDd07gUdCnS{p42DJ`5Ui3cfQH=(q@QaHe&KM^od=$`Y9o6@fIZ7H@DcC?epZU4!gk*8l3n z_Lzc7$|OudnDGkFM?@5Eq7qhD~l~Przit2?+_Qi4>NU#1Vh~Mw!$T zO^pB#4^I1CfbF{?h$ST?o_sPeP*hT)G_L@o0T>$0*_39!g3Fxd71$6{B|53Gu|`Hl zIHaTkfI4NzB;Bwi-ONc#OZ&G7QeY@4DX}p;fCQ&fteFrK!v?lD2vt8nKg7M-`ubkf zlj>Y^1IWUya}AyOgr{_{7@LO1+-e{TyZ@HwKe=Y;A2neE7g{&i1L*=L?mBIEY$dw47=r zBqWQC>}rElad~-Y;r!g(Tx;v6iF~E4q103k>y$#f-LcnDb!Kvms?e4eZx@%^N1)!J z``D3qCS5^S*Q*F(9>70Yj#t74Km_^v`c_m_P-66CNyZsD&wuY9lND%kJ=qKacxZL? z>SU|0_wM!0aC3UGCh=|{l*$0BR5KbePvf+90F7Z5Z0+ZDyA)Knc46BF^jmx)Pk z>il@@AC~86XlO2+@>CeXKn-CB@Y?On3~uH9O8ardwR;00RIDeIBy~2`rHI7M%`NeM zJ-1K2-obRYB?OIxR~3YOUY==-*PWlew7(rMckTL;*X>akU~`w}bJm8GU>yM?bar%P zV`8##c79x-81_+3-#3fefNabdr|wM@#5FbDfyp%7KtLt3v9;ZvD46Pok}D`E__r}= zRP$b~M@#U;h*1E)=I-W#gN+Rw1qE`dN=n!m7<#6U7d{5YN3d~rJ=+6N?yk>R*w_Hj zUjb;sV2^^Dnum*PVthOoQJW1MCora_;l^CY9V$0E`dv@z-HpNlhS!?noQtb`q!@;{ zc*FW~%%t0Z_ik-%H2z{*vCv05Y z6Y;*xsz;7U#rnt#A zYV86tu&AIi*SGe+y4ojk?r!vN&e<($?Wu`~h8s9y8QMES%|c}nz!pQ_&fFyVGEGKD zxBUf*zP_I$`PgXvW22+``oQ@b6(8Vx3MC=@+h9o8uh!2t&VhjlR5IfZtXfb0zWa`; zbugKRp<{2(URQBU!(O08n5%6=cPwnQvFQ~It>Y@9X~J_QBM`s0_;sg^w*z!tdHNyKCz zkVs!qX`UD;dQ^0o1FfAsG%2)ZQPA$)3zV4g`C9bYSSF6HD9W#5nf^#Os()F*JX}GE zr~@lJs$T;BmoIYiBh!O}$#|@Y@bGx-FN}xuhDbPhB(2@!qsLT>OcjxuA_)V15eVHI zy@=V_YrR{lQqj<%@XX{+>?$f2i(v^YE4!h!oVB$yB~Ck7jM@+*Dm#00!h-w{GwD${ zk+BwY0b@DP#E>?@@$px0@@*%AF*zNPva${@y4HKd#D8)uE$?edC0}=2q9uuB4Z9mq zOcn`wHdWr&J0ha^2a6+rMn^aGhhH$Tuz2x`LHgRdjJ*Yh(qC2pfGnjX14D5j>;(My zahwgKq{YhM>?kY~;czv{Fg?ei++ZtIPydH=v2o^da=6q|p6}#ERMhaWPb2U2Y(_?g zf23f6HVB0Gf`VVNTb9S^i3x5zwudG0ZstYDeVW_>J4z&=pk&h!b!re46%Fbj9y_Qq zw{eUiS*a{BZP-n ztwP!w(qC+3cm4p$qy>%Tmt(LPlf8!Zg$ICfuBLsehPkIFdZCz!mk1Viv@IvKb8{d! z_q{Fi=8(1h0WvNbC*I7=S23Gy45J|{dt`|pJ9D@*GvSU9G6>|;7*(P60L!Ofu{b7j zr+nd1CR;KOk4$SFca*g*{Ubd}wysDJ2lERnzkv;G3N*acb@9`^&^Yb3OmWM7K8mM{ zi}C!#ot=n?J}ur!8gc{^bJlBhTO>0I<72+jm`~v5=J~-c2__(LIChi4#Eb^`tCH2l z)s!2HVKUKtYhom^hU4}&6C}B}B#wv2f^OUx7#KJV>Y3X>N(a_9g6^Laq&r5LX~*44 zUPYZqtp+*GFtv(reqc5R;?Wz*2bW%tjrsb*MMaOSjjSE1H=Bz=o*F^SnkEg{jQGh$ zwSZjle`8^zr|n*_dEUE9i@t{>{wKv8jSx`<1_s~wu@>N8)bq<}xgE~`|7qv{&pdu~ zm>}Sdu@bkhG5r-^ryQ`x*(fO}=+!I5#^k@+5#40+&x<}*7r^{CYI!26pe2M%nglZ> zIGD?MfBtB#3sx$H*A*gC6MpnJyE! zJBrZ4Rh{09B~~mDMrvk@7UUFaxRrG)H!J zWnIA03Bh~-6c!p10!#tFw*SI#f`jEp?!R-{laZ4jEHqrSqX}r%+Q6cr^{}(Dc1H{V zK*6ZpSeu!-K3ip8U0n@i#E&Bl%a=!M(Nxmc%f4uWLPAQXUYq?1q~5n>&CMjO)s}NI zsr<=_iRwTvRZzgh#?Gn)?CGCo1%bGf)ak_|YH9+|74Q^~8vs%{tmfs=VdS^Wr|OI) zWVJAn%+1XH?Cp8q?A3VPT^FfW?M&%-6Z3mqf&u-~JIa;+QLNLlSYbSL{)<5~`j@?Q zp8oT##Oh5q2vqDF0Nan|!hcW^IvN_E`7|3KGm4Ajvs=X9Dn~>_fK7y1UGH&K9vK-~ z8uRgAECi31f$$k{GNua!KKcy!Z$;rtr5BKii0(@QI;dTt@`^pvN<)dwF zg4GQ(Zlh&GU<5*r{dL(HRDQ=m=>^liztlqd-p%bA%sX%bVIO@AAXx871wv*&J$evd zz-CgVS60>d`0<^~;V1t#LJq6$Y64yto3WzxfAJNlWm6Q@smaOLHsW;HSy+IY09Y#^ zdx|4GKERU$7EZoQ;1eDmo|)q+^C?X&Eq_=mLqkdmt*j=%R8WbzPk{yx172B;`te>D zssGcI0P%s-{%S{RZy*Rox?8#FsFU#Kd@ovz0$5ChEJjiQ2s=8Sfk<@i{#G9VtO(uo z+}!TTNw6<{VBr$?A7-Yfv9Ph9_W>bXx+ZFCWd#})Wd}Ts+S=N*v{&hJD-PAb+W@o- zgv*h(!oqc*Vq`QPfpI(%|VN`i3z92rOlb6 z#JFi&dwYi-@G4LN4?#qfQw3+w{MWBv0XhLZ8Q2)YQm zFE7CKfPeT|(`yGTmXlL;p^UJwKd=yh^iZPJfI~!7Snmu2D1(6gWWulN zRUMY}-8^{)b&fj2mNwOv-8 ziHeHOpmzf)yrHfxoPf;?7!aV<@USq&k^4&1G2k3p>FJdNksXXK{Sf#JUf_cU&+Wjn zKBj@C`}3MOZMSWITy439hStu`P2kt0dY;b!l}O_%F2K*v#ob*tm49J+n)B7G)}*&c1KhU(E)aW^0SX`~LQ|PymQb zS@zGedo`;t?3d}U#mh9YUU}vfXD14hk5fs@PVZN0RGF5VKLfcJrIL>P2_hmQIF5S% z!~U?h-<{PLiWR#a?D{s)-SP~^+QaWzD(^?jd#k6EZ!FVL-j(RvvE;C_QLtsd$DUC9 zYMq|+yHzOrZ@X({1b^!Dtk}-Qc}%rL#>d7qn%t^N>BCTfO2gsH*5xOaJb!a3U>1$DoN0?Pap+!aA3vZ{NQ4=aDd>Ug22V97yu-i*10JiHJLk z=Dd*6cm1Ev$Dit>lJ-d~nCgL_l|`yNTH&@%bfLI!wHsZ^vVWwBIy8ai#0W3Y8)5<| z#=RqMi-65gGDXmLkqwGE*{a0M?gM+%yhfjiN(M4ptmQqIH=#S)F9>BrWl8OAn6+`Wad-xRs*KN9)z}4X`h8uG4 zQxB!($aEps1!_(jvfQ2=E=#) z)<9BDNl6K`b-Z_wNPBQPHA3RKk(Fqh=8GK!QArDLFoWR<;@X#6FXKLF1{@B(WKveY zJbiD$9}!}Pwe<6LVGk(}E{V)6e4p!F+}%W9L<(5CLql;*F?Z}9cV|-?_R-V}*t{gc zd8((+sra9z%8#~9iRjCIGSeIxJ6as3s-oh& z-1<3^|C)w|CI}Ng`G?T?j)UjaSJnu9(%HD0N`@4fG_9q^+1c5(uE>*`*YeKoWoRZ^ z*CW*~+@ArcgoA_oXL-%+d%_`510>BC6U_Zt%rBf!*Yvr)J-ynK;LI{jIgQXsJ_{^-=Y}mrWG_+8h<{L(kO-_co zyWbm8>FFs}kz)Eb@){VCk;75Tvd3Eg3q?mVGKy!03$`0dlKjt>iO-~#=ZHk(^_TGv z?#0b7fn#EkuYp^8El44#j1%wz)~AqODkh~TrS`>U zf0u9USq+t^JIG`ijMl@iw!i!!|E1SaMM;Urt6Fy08Qxh0kEUE6!&`O;NX09+XIsM z+?~L&4vv2y+5$A()6;{V4|3wa;O%QrpMgDl1z?SZrRCb%8Z1cbAi1FtaSr$Q)6>x8 zuC9y^0K^NBg|3Oo@8#uE^Qq$OpOw?dK48Ou8XADe6col7(5OT63kpDCLSa!+QDGq{ zvB@Wu(GG@WgcEWAe;_d_>8)BhsPcfp132}kFM=V8c8k{nNPPEqH+xrj4f(5j+k*1w z7M9pksCa1x4?~^s!os5)U!G8E^i)(?{>dmUEt?-i?dUKu`PyuNmi*$sF+{|)WWICS z?u_RFxDKi%fE=BZndxydzyUPAWZ*%3d4}xA4N9KCVa7;HTj#WwSX8u^uT-$E!Rd8- znJFI4f4S^CJS+zTj1nHtYX@LzfSe1&=<)WvB*2w`Yq8kid=No`8O0Iz|YcIXcs+C-@%uALhgfK`R0?7a<7bI-B$I2c+R|b+ez=HYJc;1|Y zSHKlD=z{7Zf#{|OwJrGWbj#dDtWT_~1C=oGnB&gH+N2SvF(Ge{T&C9mF-d>DefZnsE zlc>HuRx;7k_b)982nal6#cB8U^#MQ2?8G?d<5axpd?~C(by_xjg)uoJYFia`xoblr zLE{PP`JRyQv&ljzRXPG%sot~ZTMQVZ!C#%>zb6W282vC6S}vdPx$9lo(d#f;)-{tn ze}1_PhlSfdgFiBI=;b20uGPTg%`cPk%kO!(ZGMobutL39yr_W)h1qx+zPy(W+XXv0 zxjrz}AFGbk)bL^W`1n?sk3dx#APyBq15ry1pp*Ie`B6=KfI|Z_&+B4bl_vp%>IiK!Ggnt(!9R#wVbu>;1)0)jeey_gDE z33QB%v3wG8$}|7wWLWM98@2ktK9i;jwXm=VA(7F>#=@HJmDa`<_?`naho~43!i0Eu zg@7U6UY(q54w&!ee8^M-l5!#-*t!-L^I+41sDFll&{wjv)baqRgVVtx@y+3vDt}~L zcmxFCqDoRkNyae_cyT(eZEZP&c}q+rV6``G3DGv#984wzV!ooHqOvm1y-j)dzd?Ul ztK&Dkyqb@8$?DV1OiUTAF}dlesP&S#pvJU3gu8b%!Qi6w9bJ zdtX9BLaaH^#Amze2TBjYS-1D+Pqp4t%_EXe;02FfCjV6D?pjEHvbOlSB zwF>_P6lwy}`EVg~X*ztNaB?i8MqTCT$JdDG{mxr4Fd@crRCFin} zzJtt==$?|%ru+yq8?HJC|M~{$bvYz&CbG9^k-8-PcVE`CJl5te9A0e&MFtizTwipZ z?=dLKNC z&at4(izD>|*5ku8+X0&?Zn=u~Lkb?(ra)g0LBhh-zrXFg_PinE(a?hKBK`f=m-xY- z;a2tmZ*XJFQZ$I4E=~}mhZ>8++yNA@f z=_oADeI5T$8>$h=O9~zL)7J@@8h3uhPbyzfbrv`K=w|Hiw;TXF!xz6S^dEM{&s@Gp zslRpx20vLD95Z=7^v~Q(&D(6L4_^E*jYse}^e&mRw^wrK(a>eJs@nwxafx5)5FB7SU%AiURvo_#}!Ne8A8Tj zvBmfNU$GKvb%i}OJj$2PumLFTGZoVn2!n%v?WOJ>)51yCH~x!V;q5O|5)BHlTtJBWkOrkGI z`K5Moad!_Cm4nb z@yy51@2Rx+&pb75=JTu3x;Uouy2xB@6qMW&Q7?WX;-lS?@D2Bi3_wiS@~v9v8mQBM z=m#!DAI`GX)=Na%sH?49ED@@xX-MLRg~7D;<{w!qDa~bIIAQMYlsYje7k^_HgJf>R zqff|Cv@QP>lW5BjzC7@TUH-2Q$R}0B@ngQ{8a;#iP_2pjdiI($uo_pA*4B7vN~m!h)XrW6Imr{Pze+C~s+9zu^_fP~{I_LHZXj4$TZW7G|{=>%DHRpcukwhx-hjTjc)^hpC68BN2R|a diff --git a/ext/picotcp/docs/wiki_images/petri_net.gif b/ext/picotcp/docs/wiki_images/petri_net.gif deleted file mode 100644 index 4989ae2543c330b03f7de63bebbc677255bd3676..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37925 zcmeF(XHe7q{_gu<0)!Ak2oO3#sM5rshzN+GcW$tubj1QF7@A^(gx;hG0wO}_9YT=~ zh9c6Ws|X6AcSr;kMB@p1ueJVb&E7NnJUD00oLN40oY4$2yx!OMV`yxkcH+`$P!q7Y z4FDhj00SUq0L%hnW(BiAnOWIbpzN$LIFy|O2Ipi)AmN-`97t|XE*>N|ii-!ujpF6u zB-Ptb7!6QB^y3 z{Di97iQ^~K)zmdkXq;5n)Y3S4N>dAa@)TAJt9?pa2dk~Ct*fu2XP~QZsApiLZ)j{_ zWNc_`Vq{`!Y+`0&W?^dnmzjm7`CnERmZ$%+I%9eItks#br_Y`{LprQ@?)=&F*5}S& zIA?wF{6*UfHg*?n?QQHFYU{Oum220p zUU#|X;(Fc1?Yip?7q^?PH{9KBdfafob<+dqe#_It(;MgIUBqF*Q?jvon1YzyL-EO`nr4jd)^H6_7CA)hJh!Kg{8U*E$x9cKhwud1l zP11}ivR*|A9CiEHRgwKV7Ofj8VqBTiogjOr$gaCGw>KH%+>>TpmG|bEn)k}b?yCHO z3~UhWfJt@1P_|KmynPS#`AELyRI9Vei=uO3G#qHG=Y;|wZ`~frA$-^xT<*{sW8eGL z^k(+NT#zg%Tf@btB$l+|R_0ca}b@y+tWK zXL`;28Ku$o78dBToHcr?{h(9it`!K+rtxxy4tgm1P(51mI_bvZ#(^fkfePsX4-ZVb zoIINoV8U1a^4BjKnFlT^FGYDJukj%)!~X{eO2qq>#9{fN4taK$`|7{;OABB2X{oKZ0F<70=Nv_** zcKbO5W{Quo-?5I#5R?SLU;Mak6_B487o>)f_P(0*(_IiPFZ~gNa6V2yCgz@jrFK6i z?%rWzCe_UugVPfWFF0_sMUz+sX^rH8~$olgLw(C15iZsrQl4Fc(7t|jItXods zaCp}LcKQ0|4mGqa8)6hLaaxvZkkpPe!4qCf7Viv4H%rf- zCLEuAj2bwKL^D0^oFt7p9u;p#4G1$wliJ|wP)}xlZ^g^76x*-Tsn1~dMPlXUh%b1V zrJZd zol+FXm&TvqmddVGeCo_m%#Fk~_<>KTNXCzaOxd4jhoEIN0A8H9ydkYm88T8PJk(`C z8&eK7`^igdT%xVb1cH2z4V+`KF4;vkC47()oeaSbHdWdZutqpR0uxs4=&PgV%&Cr2 z2tZ`O$N&31$*krrJO}`zsZlP}{xd718ER)!@XK|Tftr_sJ)NJpnSAA8HWqB?UNlG(wm^61WcPaNT%|&A8<7Hp5gP z{=QuWeqC=)TV%K6)RI6u3#LvD2nM*2ibk3`p3JMSm>{(P$AQ`K#~KSm_rMW`>Rosc zIc4zClm>M5>x`Jok`u_Ei41cS=aTiAk)g?U2x4c&&A2ZooS?<3_yNX4J|Qd+Dd?A^ zR|&ro+nAZvX3mQsgWb$-F})*8VchWX98OFLEhO!~>U;t(WO0Dy&R#`YpGgFsYco07 zi9kAW`oSGcz&g467zPjmEQjvB?;;EKN{4aa${+CqOgz@zBF>|2eD#AYhwstYouIk` z9dy}F5rA|<*30Aien7!X&7p`>aFnBssqBDN^YY2V{@d$qCF{qH4!Skxl8^?%v#0T4T`BSCDXIaaNoO4TexT#W z8`3kd6P|zVvK>1lPv&+7S&n&Z(L3v&~Ax%3h;I)5BsTQGiL^q z*Jaz_+)GlRM33qML-UninmVtMGFX_CRi3{5u>Ns^p_n?+u>lQ0INZW{yt5EbEDO5>(He~xX@U}zf7#2u9I1?-+PKh|tIr!X# z)d_641F5$AnQ#jWQd&sQQzw^n-3`Y2zAJt;QsZ;WY~}vJWUOzs?ON2$WA{^niC-!f zv+%;2L6Z_f?GhNau#-)rXztfJBA??Du79K`R%Ww9=}6ku8>00ACqWQ6z4s+|Gk1ulgBZvs_+H7Ync)5kkiN8ikp|3RDq;P!rIIMxjIHk&F zGqK)eed`_wN7|)H5s4M`T$Vw0OkBf8@46*&s&Mtt)IrvqHfeY}>j@Ezs8{}dkrvU% zR)Ka$r0VoUI6V@sl%#nEh~r_`JWsMdZetBKZaplL5~)0*_xY&nYe55%TW)UKbHNS9 z>IGDa%boQbr2cUA)2cjuH2WBvQxJ3P@q{xsIqKOdttw7RhS>`2%M$g$W7!8lveldC z$k`KbuYfsUG&{t^;Wf9Oe0}i9sht(QChPoy3ORtN2P!uG2-_K6Zz7VK8R<+hlt`FV7MV0$@Q%Cjid}h!dgoTJ@hGcB!~i z@|O_2mT+%Lb}lH-(%^~1mpCv;kO&DR;Dl!q(xugTen0^0vtWapdX&t7XHH>RW1)zIFJBb zX&QDmIS6toq?N*54uGaG+Tjo(c{SDf_7LJUj5p3yfdJ>CNRD%Jk_JN+VJtL#=@h=pUjKCYFN)<)FFau%PHW!8vHqNSErnF}!iBM;Sr)0GjpJ zFxMiMMIOu1+lBlY51+jdBjSm$iUW_LW#5d6{5k_cBB38txn?k|Y);U(HA*wY*dGO4 zGgwwOOQ>|dT%(cLPi2mr*H9}%t|cTCX$g@Xw9PhcdXEB+rJPjDzPR*}E~JVVy=M z!zp>d(-qaH#eT7ouI7;t;WsFw&_e0*_>|{zhNYno%%%^9)u*Q2O(iYIxrBLDTzt0q zIko04{3a&!1_4g+PULibMzdtEKEsp%#Gd2gJZuT(H5R_c_N@H_uQ8G@8OL{;g8prVL;#;@Z1r5|D{rnb2aXC+`ksZcft4;F;%neFC8IVh!Q){9C?|Msx6996 zd0IWMj2nuEWtFetJ&Mfvc{e?(o!OMe@ioE$z}zu|Wf+~!(c|J|GRd{o1~21sc_Z~K zh^P)rb)QzvZ!EwSbY8yTb2|{rR9&XG705Bs5x{}u=kl)KP4`SiJ&yy@bXe#Z41ZjQ z-0(_nK@~qiEUVI`2PgOj z<@vASQ)cj>ECOfoP^ZCkN&FTVzA!=_G_t1yb@#LW1) z_5crOooV$KF3t{15E};G5>?d{$*Mceq(G00V2W=#ry#LIxHY7~cY+<*kZ6)dvrF=V zLv6(@d^o0TBbvrp!v#g(g|;N$a8D*bTQ}vC`pz2uRA@V@;T<1(SAoyMhM$1s+p21Q zr%L{=pb>=QrIG3jd&yO8#rN;?vT3%Wel%98%k~eu@Zc9k1 zdy0v)38l3ej5EKn5o_v!!nL9Ig;3eK8<7`68o603V*iB}GvvWf3hPJ4a-64*|>qo|`e6_1?9yB)@$ zHsV0_#a;TD&W~-S0u(h$uOiRl1x{F#*704bAI-$!fE;j&1rB83kbQ#(eB%qSnTV98 zSA~kG4cu$r_~IhHtSlUIPCcVNxOcg+xBaa3$12bSi*QrJBWA1Tl{_rE1VnxG>mE(B z?A5Xuk(QSykT6sJ01dN6OCz(UH@$YXl_NkY@TM{dR-}i|0)d(_s0Dogcu7Co44X!9 z(G;r1i^nM3#U#m^G>`9h?Hg!EaURF%z2EKG?9JC*s?Hklm?oFHN(~;LG zM;cvnF*&W!L?O}#Bl?DJ=dd_2Gncm&SE7-|&L-%=*pnaxFKI~ekjF2D`XXdY6;=KL zmWZp)Re#=hlEb#R_vFDr#4#9<$c#AD$Xn@#nk0=hG>w)@RYYw;woQ!5$^DV8cB!2EDlZX5#oIj_>d*FYMllI)_Bh zj(4te|D+GS`5X_@NJF8|d>H!VounajaJ{1+hiPp7th(B|Ved#$rXMZdO>GF+VWpC3W~r&HMle49~z;R0Wq zDXU)4z97(-l(cR<0JE6BJqnKd**XR=X{bz#P8v3#LFvt@bOQV=7M%NF#&rx1Q9}Ok znN>@lRd1QqESv3#gLmWDPHN5R_0P_sXR(z^^(>&fujZQH&RNpuPH)Ve6`eoVVtvMA z-X?wC&VL>^R6p?%p|7=Y#bM!^*23012e+1mo0Gh30BpsKqyFu@?Z&*X|DsR&;_b3U zI)H?~PqcG)u*ZuoRexESD0%Y8d?~VJNjE{tXxmDWbvagaIWb00=lt^H^yQR(FWXB? z6Pg?m{YzQ>3v84{&D$#l=__Ammm8y(cxsjtL|0RlR!Lf`H4e*c#IT~4)utH7dX~kW zn_9mz}nY0ZiWqkBu)a>m#DU$Ellu7!`bq%Irvm z1W=(FRA7LqesHb5W%J#}daf!Bt9H)Whc=@rf8zSXlSv|5~n^(IiC8=j^k^? zl7A=~l~ZA*)Xx~Pts|$lR2;Wd1GdyMwn{0ma;Hioe_cMYZ5>CqQvuq${Pq8YA66GK{4m?(Il~X%7GJ1x`_%KI_RCb^AjZV4z)VaQP zM@`$g!o~ClUzZm%@DTYW;)B4;i~fGxMN3)Hsw?@Kchu#Va}xRP75LMPDnjzoJXT!u ziT?6#1vxQpZiNNusRwiR-ke!3rjz7*iu^zOxviF_E<9BzySK4YTt+xr^NVa0eJE4#c(E|Ncer**)NZ4d`M!xs+qXCE zdfY~`Lmk|vYOTTCrYf1tJQnygJ#Oj4@xj~*RX-|TTc}Md_bHddy?YP8?mOClq!I4Z zdr-3C2$wFDrpu{07g+I-)^YT&(KDt8Uc9~FX#eHy**hn{ytBJ;;P!jxphK$fY^@LE zra0C7%pLW3?JoWC%n}4K>iEt{{{B{0{ee~ z{r`Pn&kTLg4nKe)b1=8QCUO1WvGySGWU2}H2$92Uw+(V~dYH{CLKT{0nWSxJZUy#% zaNs>X1q9l8xwtujYNmtl$$$%h)eo7wtl*RgsxONt98EGs2-7JJ!iNEfO#kC!odqF> zJmT5ysagClfly4acJyTtCc&-?21iqA(Jn^1LT^c($4Hrv+;6rEPXUH%o!SWRG^PW~ z7g#kuit}oHzb>qYBhQd!!3LN^qSJW5VrCivBo3pe;($#I@YjYkfReb&3Q$_ZG}kgY z1E3vf7y+uU7|0bH&Md9u$!6{|!;^&$k+ZCbJWtl)t47Ldb3|G?G3yGn%Z4hW8{pSe z+69M51u7~%RvTQ%a_A%8J>GalgsPB0bk56O{R_9|C8r?S z`l|W1AcCMRQdI9-I84;(?$N$!mc3G?|G;=NJF)9}o#wtBW?ZtQX~f8#7W;1E8ob;2 zfVaSFIdXf{dsF1CE0oq_HJ*X)KV}iHUjc{5Ue%q4YqiG#fP9NyE$X5(fVnIsZgeC; zvRh46$-3{Teigk^odNTTe7couA)JxeV2QD({d!$h>EHSmwf1%g@QCX4lUVazJQ=x3 znkaUeu6cghsTW(R&&9_bYlztlM+qF^WKybv~e<90q7 z1PZZ;W_m!b2d^lbrb-(q<7`qQCZ68 z$uxk{{VvBS`-FYsQENL+JhzeYfC+}XbVu!Nri*^RBy&-f!=dyV=``p0d!ZA%7D}{r zY26R}A8hnceRVOnj5>tIZxc}NIx`g#d;NSu3$0R4uJFC7#uVYrM;$jvc`RXP8mHAQR8J!q8BVZ%o z16jDgKKBmRsYAuefE6(o(>uW|h#vfIg!R07TapN&LN1d&q$lVbyRZZb6k;k6 z%IT%%r0Ev0rxq?MRV>wb#RwOnCjUvM+wcCQfJ$bzk#BetNrE7OLkoNR2NNLe1p8$zHfybL zv=z>r?CcG?+Kde3u~L#A#LCaA2nZN~J_lZq3_3iG@Sx_N#_2#D(d zfC4}eo5y|M@Bvr)zYrfA#z1_Kz~PSe z8~;T7#zcK{hGIC$=gHkMAGyWEQWWpc8KW{9Y$Ckk~{Q2H=CPr7!?r&L&;ZEsI&5|4;*Jl6v7c;AgoQM||CtX8^vk!5_eX*0Ga? z6w3DE%3*MQD>97%_z0UUp5%}?lRMYe}5(F6uuh(z&5s@f{Yt{d$G zzQ^}GoDFRK?xXYn0Q>{t`+z_H;l|1D^2!ao^s5c#K5T9$w41T#Yjz#~j5d zZ;jtQIJCLLwNJSxuu%k}ENj3c=-gZm6#UKL3Fq{XRv3ze*-?Qw~7JyicxyJfZv^BxxGJtFA;uAxYjEe zn%v1-P+gaLB=2b>e>+l894HFhdqMK7u=8Y1y`Nw-3c0Vq9?j?nBw3mzI8ni{4ULUD z11)T=YoMYQ?#`07=sWGUv*w!->%f-15_{a!W?M5#;t@>}lCpJ|b zsp|hD_?WBj*nu(IhJC?Dnoh1B(q{*JFsRoPAcbV4lx3sWwtP=M`{tgKb7Vu8>)(RE zYg#vL1m}$d+Nm$yhYEZNzXhN4h$)_Iu_v(;?~T;tgMuKIiYO_n!%=M7N->=bZSMvnK?-qsmF!3oh~u8YGm*~cYkb2n099hNXTl~SQ7Uwh@tJq~H}y;~ z*8*gaq`aZCP2rb#sBJv>{vM(b{<@)wUxv&ZsA#%Z#0IrOOnn9GP9p?~FMG{Umt>mt z!F`p^b`Wir@S!^c6Nv7nHxtaAi?CDN{{(!`5(eOZ=<8l#06xCgmr!1*lE(miNnzlq zkoitp+n$Jd%&U{act=8Y`2k}jue^p82DKD7P~S9oU8UvFUSH;q45s*MpXtUSA4Et8 zy-VcHV6}n<#~_SUQC@&HHIx-X4zlZBLdZ1_DcGB)lXUTfGJ;AT1Mz#7Og?;TnvWYU z`ZzN58}a$S_ha7ZYmw{(DGbD~9bX$gsXUPOc`)!d;%6_JJdR4EkVkvg-u^LsEqRT7 z!=E)lQxY^8hCle$qnT%c+CE$i%hY5qZ)4Si88T|&gVMo(<})->%SUhUx@A6qHKvej zqIk*;ra2y#4#e7zvAKK(r?FaIE!OAzRr)PxA=)SC#M*W|E*M! zEiT>|RNuluVK~0VC+9DklXHO)(UMcJ4ep=QLkz~h&tUxQPrMd9D^AVX@$X{R;H+Cy zVl9!Wz^D%hyf68;1eH%C~}A51R#(-#@K9#97Fj)Nzom%`JR2o?xGgw*O~dnEc|e3|`Yhvh{7<%IO* zq_XA2kmYCe<#f@NGz9;r-l28k5(C(aT2=}yyb)hlNTRFuo@W)zIo?UH5Vcn7TUP5P zR~t4~8H_)F#i3HkkzwpZ`m5{*I7iW+y69_zS}MkYdaefRxa;d<4(ki^njiev$2Zm~ z{k%ObgCmr+A^(kvbf8V^+S=sC#$@4aS$|(YVQO;ytHb7w=*F)9rfodXw6nng_H_?? zqZe!QO8dZG2?DK_Q4yO|=7FIF$pubF8t9h&FAti~<_6a-szD14y?F&L#wqSt`1usy z=7c8A?b>IdSen$pXUwLI?90A|Et)dtmeK_ExY(Ah@*w0dn#RCqrA?;emfHpa{{Z%> zZHr&q1`Nta(^wh&e(Lkbq%SrvzckbgFF4z?Bfnlg_4SJ5*J}Y^T{6D9z5Kc_`Di}# zn3BM4Sot9AcEC5kjBoc|etR(W&HvXo{1mK=3cEV7biCtBc*f4hYdej?-=cr*#EI=b zKDFB;_`i|L|5E;cDgVEe|6j`g?^gc5TlxQP<^MmmmH!vzbG`m6)GN_5npIr&DbFvX zAl5jPx%CAnY@p?>i<-NC$(dpCk{+)>+6A54s!kkc;B1J%2S8Q8i>+J=%{15;`*={B6pdkO05|6cohS-DHVALcb7x z@@oB)2S=nt|6^Ext6OM)SYO)}qU1Lej`m=ziu z>{P9pesl{jDKd)=JJC;w@hJ&9un`9n`&q>yq2}c2gaS#X@WtY=z(E?071;5MyJdvG zBT#qn8#e$8(eu4-o9U)I2?G46;+*%F+Qq=i;W}s?t|+GtNeS%;Q#&1==R3i&Mweh` zOR{)LaV&>Kg@z)|qXb%!otVf=(J@Lvf^TpJDhBe867qa<4?QeY>zRg&$|8d7*t8|S zGxg64i<>xFYbp3FYyn>o+aGSFdUVB)+T8|6~2%D^+Vqukbfr|IPZp2>HrPYAEcU3xY@WKjSGPC>pU`W|3|musE$4u1)%760Z z3yH4rkv>D_l%X(0ik}h`uN@>b(~(x-TxiH=2&U5oW6fMP74^}McTN4hfSe!VV&51w zfJFJb2Gs7?0J{f_8o-=x?EyFzM+>2WH#|?bV<5RlM9q`^bPKq^=_$_ePrJL!F;os0 z?H>oH@L)Ut7z^JfoA@m#VWq@6D&O6B{X)Hio+u)xW^;}k_HrlfVSMRx=L95Q`K}!b z7j!+%UeEagv&=M!HBVHEHo`u!G8Y$?ra23_zWmt^i-%g5Ck+2wWy3h3uhE}4p~3>< z6+G|>2tN-~l2h{+b<6tHf}prloB&I~U=}}H${AfVwi9`1g5k(jrdznhq)8A6J)$Rg zK+Q=b^%l<+Jeej93P}&3$KZu-ii9sC9$N5;A875pI`K&h&8u`tK&xvSPrDGXH;aE5 z-*jZ_v3RTW>D~KRSzbzYWA8;7@G}#^Rp>j6pTV`91mvjfh(uVW0S|{7&pHm`W^jAC z`V7%f_INzvtkYHg_s1M1eFZWRaz}Ym&IEi>e)t;8Lp;ipPdfJV1)z!HC_HHRlmD=) zC)>mwPcDFEeM_FKd)!)*he}kHzaSPz!W$H*7}s%)QJ9_{bYQfB;}^t)FYLDgmD;P` z%GaB5A^&Uxf9<$aEkiE^h3>Zjq|K@K`)%NIc+fS-gMYPwIQRWFfD2=^0s6ni0b=-n z#DM@t92hZQ=2yM=zlsC5Q$jCH|1%D7YEhv{-mEWfAO1Cjn5S?I65&N%VyuZlZ-X>v z-WiSnATou!Z16#)A96qdu0(?&sT@2g52A9U^BJwTe%LZbps42VLV~oi4$%Pig)Z)H z0Mv$wiN0*A0~P8CH&q=Li-`j-5VZW0{xtCo+3gJ_Y$#p4kQ z80dDL1?NTP?JL}iRB$jZp6zig#|geyJj}zo+_|5l;3$;mk9EI+vGAXDzrn%3*ZsP+N;5#RSK;65{`7n~732MNzgQQv=O63-OvbvOkitt$ z;TuX}toyaQlI|`A{QJ89ALD*>(x*Cj_QllvU1Z_!alfj|le2^;8NbKd(NnQb4>e94pTI?X@SHCtYYvj%;w?i%j~>6ox(+8gmq=^p;dgiDQbtoGBn z!YeuYsoCD*d8X4GnJfaFPV5&=a%}IhS024;24cDJ0=&5^D59Qepw91e?@22zgHZ+O zy5mpP>$1uv^6|8MBQ8#rFjX|=F=N^vY7%+eEzh^Lz%Vn%rHWTxFmn`Oy@e^tu_?+0 zvfNv9qpFzArV-L;hj49BCnVb$(u|KCXtBpQtlC{@l*3%y@{6 zjVyN-VDbhTr?mys+)`46Vhn~5F%D{dYu+pfmg8{}6)K_^^9MRjZxQY=5zB9rA zzUZnjYRhIn3@|I0%As>^2?HMAF#JIiVwU8q8AbJ*+@xzj=?wDRpD>WiUdsprPK+>MdB3DsF74Ux zWq)8)&W#2}7-;O|E!l2N<*t15Ck!~1*3dQTNfp(MGSJ_f#3%!U^8YFWUH>QppZ1!J zP|f>gK>6~QOW?6*&HH75+7hH(ZrhskcNxG(vl3dolo7O~ zPix)}1D2-TYlqI*@-xD~-UP^=5eDK~7-0Zhz%Kc*p|ZW%@5bL@;81kqKd1di(~8of zeun{cJkwBnAR`P^+}1aHEWWDbXA7>xo)wRK`DI$~J?0gnyZ#|#T7FQ%wuwCN%cczL zyuwu(0F)Mbc8WB4-Rg6GQjzyfjE)}>y z*lKqFvDY#1CdRHmsITkEP2S#Z3GrgT$9=D!eJn6XR)1-&56MFY1LfM&b`LdsOs$yC zG+2oDM!}{z*Z_{fd#YOS-bXfnCxM^8lR(}Y4%;;0A&UgfYt*3E0F{lk75>SJpAJK< zFt+l2O+z}d1$t{GX%D8N2@GzR@u~lFTUMA73~v3RW{3_V=!z_}28z+xj^+4Q2s3 z>|a)gjuTLEl_&y}9m1yhjmIN%8ji`ZBL{upo!uPMrzfB`6;wszV8ACHsW)<`9u`+_ z!3a5zDz7y8u_GQf55zt)rV;m-{SkkvfTSrJle}LAC}SCnDu8|sDS=s?+^+%`SPUCi z#?=o@5P!DrCjnxCt+p`**%0Mi$w&g_&BNs9rXh4j6TsCZ>Q!;N*QQK=e0kv0@j3P+ zMiUtP-2^Nj^mq;bZUUbse>VXFqX}T|F`7VBb1^Bf+W+TdY2rs2l@P}vmnaSLei8sC z=!_%~=k6dLhW8|mpOhaXPo+0g=Fj9lUkL#$!x>3n`r)*Ig(hR#A1QN=kpz4-$#3zK zKTpmul0amhA{#Z)Si5P1W0sKwZvMO~b8=dAD>_NaI&{~My~?? zEp^u2;rF;7JV%#_U-0*wzY}u|0T)1f#wG%2C0o#sZNScNeoc3n?;jqNqwLZ*fm8cQ0DJBp%U@JT z2GwZW1r|U>Oi^=_&z*ZUIzrh51<+>Ffvt3x{jL0|(!G|UpJi8}j~3dKg$Pv zK9~V)?a&xo`2(8{JOi7&hxfPgj3yvlzNNLfr7|$OAh~?Xaa(!Q;qa|(lTDiT%aMgM zi>6{w_L=&+G>wjoZ`@X z`PKT@7cCsqe^P$HH_bS9oq#Q`Q{T=8;38k{L{CMBY&x(b_bEToaW^SoHzi{?_2urL zBv6c~_>%gw^)ow|%Y*6Vwl!rz;I?UBWPw4M6F zBlLfs1Yl`~``1BG(*JfHU<{q0jhtJp_IU+ZIW9y@U z{bL=ALTL+&@fWsAo-ZoYxiTDaIrCYl$r;V{`BxY7 zvhu$FrMZ>3eDyg!x@cUM{YB#Vwdjf-H(3CQrpcEitO&^iQacs-&st%{a>5(XqNQ@8 zysg~r8m*`smBZ>V*JqEfJzL2Q$y`~_MAVWnSa<$tHwzyQSjoU>n>^yf#?QDiO3({*HZqPC&PM6Gf`pF2P zThV_RTd58%>44}iPD>2VZ-5!0CaWb~a zoAr792<=D8?a7QgM!q-Gll#AoF)@`j5VmkzzSZRe$CFh<6tj#ZB19yhV)qAW2683u zHYj%9m-01>dmB9-xI3QPen1$~ICb*I+r$3NxDU5Be}1Ec9j5QhCEud&F6EcgzpvG9 z()XyZ5C8hH{r=XkpF4}?zvw@{Z8F}Mz=;5>5g9B*#Y4@AVE!&LM4d`NMiZG28nwb~ zsDT1~M9A^3R>VDO5E`BdH8g7DPNfFRnq|VQyW02~s3Dl>O!#%9cA;@HLfUI!G2xfXr<7OABH>BToE~o0~cwJBrnjONu|98dz$dG97wA zX8TgOBmVkWQQN_m=OpJ$n+bJJ~j!BkJ0=taOMa%+0rx$wa&`<=UR{q z{c5_WnL69N-s#h>^QP%ilx}}v+Wy@j6hz8i=l1!9r)t-7WS%MhITTbqbyxtZb0Nvc z{pn2lL;vmTMEU(2LGz;@;{9lTXP8h+OJDLXm!E(Y=7?Ci$>kkjRN7*~t*J#!Eh_q9o_XH(na4Y!@|MS=8KfS@jUdhSQ4*^|1(+}Y zS$`gLX|?2m&w=W(cSi^Zk39Fjp@ehgBfpRd;RbPNz%!Wz{4^^g55Ku`?{O_fOF^j~ zy?-c3as5488MIt;yTSGnysA zibsG0Yo1<-OCBOp=7Ws$KuL`AK$na#y+4YLX`>}8(pr5@pEcwPvZ(%kKA7?IvMJoT zot3_J+yRp!G_1X+?<+E5V8{5y+kwuY7w<%#N@~-O*!FU_4IExye8i1J_1xY+4`fxb zI$7z@!^eshOH+u>0Aa~^1qcL=(?x4wTK=tV!{JdoW}$q(~SIlgG_ zHJ^b(OM4r5p~1}8^Op*qwZy9dep}lnBYM=`cj43xb;kJ#pleGBQd+h?-YJRTzV3Wxk>EPg0=!jXfGWh!LWVZeNE z@_qA;YYyW~gQJAO^@N{NK@es=8?YbpIH&8aV_F{uqzx3db>N z_f<&H&>ez4ZDOuer$<@KF!mn9I5%?{*`IPDY*5R#QZ+R6ZP(BN!N;#pex=1)aZ4Gf z;yFU?+7#Hj@Tz*;oQ`8oS~Rs+Y_bt5P&6rCOv=KF?hWBsi*skZT;So=F*%cU`bmk8 zvSz`|86L=KsYGo^kEPY*{uNpoLY02I3Molq9ImLJ=x1#(SCYTvYrv9 zE?GPoj4`blA@W=`n6HxfO0D;9zYkbapiRI)Iht$WDkfX7KfLo~ZpDB<{V0)%*YHGI zYtW17SOsyTj@ePGJhODyP1tG53rPtYOPyu7k+Iuwdv2nuBFmK{=Sj$0iF^?k z$#gSKiNT2HAHLRTBq#t&Hr9hlxYpKsHbJBK32G{irObwl` za>?Q-%r}lVez#W=7_jN)wysoSyk`gtGGe@E01m-amB09uIP(kl@4sgl$?BZmyjRyI z-Wkm)OPszWE|pz*sl!Nz;w)P0cW>OTqJenv>P24)e5Feoe`$nW48?e0Vzfnn8bMz8 z#~GnTvqjbW_@sFdL3~oX)}ZE=xTR8TqP`9o0EYSWfo;hP);ch__h|t#SXjn<*~Iqy za7y~NU_Uj~{LVPXQ-p6pFCNf5*a_0IoIEbalzG1K`&&}Xi;|(+!M}#Dg3lsZ4Y*2O z4EFkmN;>cf(v0gv7%5RL>amGA$;Zq~_udW0)Ku?nLFL6#069EMYR}Hx;UQ+xhfBai zCOjaZSs?yO>vpAS*IJwu;BCci2#)!`+B@@qDF6T8Uo-Z7F!pSbveP14k}V{W-jys7 z(t;*bRBD8hEE6SU-*;n@?2V}GhLo-B$u=6L1vQ=5HAD6OEVu9Z+|KRXzTb0h{Ri{I zH9uU>$92Eo#iJ}J^Ge37EM`5ov*3CrslfAMS(QWU-b8DQ8(#qEX`%P&Bb zqW8BcVq4WMBHlu-;YSGj2&X;k(O>ua;Vxg!rX~lD!mXXVE$cqN=T$(y|-_) zU(+h(uvx1LP!5-`5aMpU0+a)`)j+X+Q|3IX$VdFtQ5G&GuaOGwibA;=%2XSvYbb;17Tx%(TSjIp;(?G!r;~&<@4;gCrhzzQJyz^2l7~`YjYAoc`Yt-#7 zqz%7JMcL(;FeuoXFKCOf<~F||yflZbl<}rO?n}S%4W<=Pq01gT%U0*Gskx=BQG2sm-knFhZT8>7cA3tC@h;p53~3R4^n!{=^VL9oGw zB4-x~Q>E10>&f+!#7*JyyTVJqI)L@Um}Ie$W+dt~HH~1kyjLpOZ5kox9MLzWeq2sR z7R(hRdU)^f2$^+F2N@?d`KEFs-N(7lV*Cp;VIxsLtNviFU*oZ;uc0E#O;MXlCBa&e zi50o0k7)0W3T}*q%#;>zI1c&k+|$8V;^6V(`;%3Y!Rtd52hve|>9!bew9GW$5bPzQ zvPPM#ZWSlDZ{qWpP!);UqQ$$-KSs+|ZAG2yfE6NK&0m1VG`M518{~s;K94c>zhici z*JApPRkIej!0cXC62YSdj4u$cik=iu*nQVw>8`U@ERS`pdwlHBv%5e?q=$umrx`>5 z&4ATIv7yVSV*M-c1uWeQ)QSu7k1IPN{Eg-!dX0cq*9sKkZcJnW%7=oBGw6zahY-6L zAAi3;K1C!U!;C3wNitVN;d`JCKpC=uiwNso6dNvAnc#Zo{@o|{>(~-e(Fu0G36)Et z`DTg3FB7S|1h)9x-%}dbO|?z5D@!`Wn=~YnjNhC%riB7?MXsh`laxjQTk?RNoqlK{sc zz@Ef(DwQHHDgrnLh$bR}()P1qnZtA*scD(P9D};&1m;O;8lPy2Pggq3F-RqBaAoD- zOB>Tl!vfJzV;n{qLJWmkOspY&=E#;52LzMx#Y|u#(w0^9@IkPZAcnSO(aWT4+GSO*+sJSPVG@0Uc4u6U6;T#p9#d zN1f3P`o{>-u3g$iE2E4$iz(EqOhwvekqS18)XiYCctN8XfJ+B#7F?%AgR2CLnbE}w zrWh-Xu$|DZM^wp>k<-9O}}+d7LTGBbohqOl=+TO{Rb@31&|ft zqce+G4D__ZSOHh6xyZ2`W+VljFKW37Y;S?+bG4Fo6`PU>tT1E8Txm#~>RZ~r5G4(Cwf343+ZfLS@y)`~DK*hmy% z{%C(|!sjZ13#5t-Ck;Gt2?UY`FcRefBavG9@CMG&28|G6We^gNs}=%ABB9R?a+u0O zEv6oRwqhM&uu3too54T>K9uEbl{YWUGjszZ5ve)>iLWn+gN;N~HP@y~B~L3^3mKqr z###@s9PDB-Osf{hdIKd~3i0SbaR4rX{Ml6`u?BmdZF;(X z_-5HvVxmn>J!w;hf=3b=&#+Y|q?(jnxV%Q;O5b~|@ z#++b1JH$A5HO7!lg|ASG^f09G+1<;z$G}`cNkv^R3x912TZnK8@70=3bz5+*Nc+)e z5k18TB%@b!g2C!(nFacQNsW28sp&087C6@nGEp#Lz=y^2OVXys0rX1<|Nd%LiS_ zmxHAh>+0vUP&HNRrD6u}D8_!eB-VWRaiaoWI*Jj>K|ZrE<+i6 zd~;pJJKY_2Ef8z#z+3_4*)5oiP#)T;7lXONO}XPjJ3q^;&KU@Q23_(@_d(dPzVk_a zAICZVYSj?In0o+%VZ@Ix)^0q?^(Ck;cCYDfyrIP!!Jr?Id)ENJC15~{_od?&Ezz$6 za(Bze~tiq2K`s+fu%J#l&+`E;Ns+}dz4DF3WzryvC#NTXbWalCs zTgL>cN;OzHaHTp7zK-bC!?#6)-^w^XF0+%c@?^|FmaIK3TR94fpac^s@2g+T~eTY-@f zNK<9P?+vo9Jr=ALBIpT=Vr8&a+`cyPjpiciuz$-x#JNpkAFL6&GI=6-(wz=4q)uWa z-kr4McDf?lNw7ny9rCBzQ7;a?yG(s|Nn+}X%G5cgsh}%U*ORA$xrI7)NMxyZIEm?K zy=k0;&(gW+xa4Vv!2NuCxvI0KLhGi|^kz~WXVSf90Ks6DJsnqPUwFkXQKfT1pR4-& zO!<{r85bG3;Jj+?3pLc)y5gg?dUHg}x%v))QkBjZR)Bt(i%*8~z1+I>$UW3;%_{8= ziUXh4k)L;vpHay}j&p3#t(T7TlS3}OdTk5%xp#naDBf^SnCHFT`}sP%oNXPm#S@El z?|bU(COY0jXWTyPk!I(|5LYQolcime6wb$P)0VAELvCD;-&0lI^Iu&ce4u35Q-q@y z*v~A8?_97e?I7p{b1h4J;5@njwhE=;4=O)?(+CZJ09yrP=lrIW4-0yp`ha8jaf+{Y zzWO1wsu7}54px$%_CJQ)!K<|O_@fqM*hNJ8}zv(wY_ zebwQeUsk6P)uexSg!~r(!=JU{&sy zPY{72jSLKS3vV|W1@|PKb;~n3x5jkjZ~9M6O(&)dWwfo=OidcArY6?Bt>zcI?-ZA1 z{msXJ=jzwfH z6YQAsRDM)kdvgwEI$~5Tm-z!NG31)5w?|GO)Q)t=Y9LUdSjLHhf!-=X2K-&+9|NqA zP)~ZeZcN6;?mZ(&v9H8W;j$3eJKSD97clX=t;~llFKTp3;xAT%RN8QUg;EL5F2=z= zADm~`x8XKUs$M&k=(Ih_i;0E9eU~3*NGAKRtzK)O0SW}}h1TjOmK7fh(kq;7lV z-p+O%!3VdvDAydqZ?%jR?9+`CnjD{w?{s3srW`dwLKaJWZ?eo-Cph1!y(mfDWD*xO z{yK0=uFC^qf}84PE5`Nc(HBW_*Wl;@06BVcEg$CZCI@=9urOZtyYa@+nB!4x6EF7Q zL8cxyG5e_Fy?OQe>7~bRtuNzaIP4TexYs^+TxX@fMXy0*NXqk6H3Bp@&WoT%W*Rk# zEbDA?mBo$bz3;EQp0eDY7l|5gw7{~Dp-$;0S|c-_F|bw+nMWJ>zQ4@iG%SAoXM(;v`h#l+5JH`afRSuHQRt1mn`IkRJ_$lwM5nzzW@YU|g+0BK*PTtf6h9{cfDQ5~1 zN93(TDBt=qA!dc;=&v-FXWqQv1_}Hr-1D6M-2P3?Tf8uW{as9qp}0@l>Tez=Lk!G%lSkQ1 zy8L)6$Cx#zvG2+mIr{8M815F_)MjP-3|V2>l`ryQyW04@Ep{PevRj#lMmm&h8IT6q zH#cizi0Ac(<(eSGTQe#$%pgb{v5i#=HJEfVNy$K4=g0Yq-waO!Kd71>J7r7eYGA{Y zHTO|lLs!0L?8WepG?oLigZnp@quhj_hsJW8Ez^+yZP*L zuf>HFyx`tI^E_FziXptOAI_k$928q88q49D8|2Q6{l#*SXen@(=jqK6u&N?c2DsiA^qd6M+s4t5H<(IO=dD?%cj4pX1 z`mRczaK1qDbXM!$s^m%PV#4MaSn`Cr7EZdnDtS^11CpnkwuoCNc_V@3NiEp3@`kRd zq&@myNS=;ON3`lEWZz8SNlSoN5^T`HX7pjeWdO;Oe#q~$$N?~mpuAj8$}K>NU@>X1 zO?)1o*xH}?mD(p9!jcdeYyxK*u)l#EP)s5A#>JDn0pl^+Eb-PqSpkJ8V~8mrowsq9 zzCN9_mt`%}K#G`H136p)$kCMqiKY$Ks}o<&LvK%!wMJDg}(ibaY|pG#SMfJs-C78)Liblej$M25 z>}jLO6c|OMTqUlT{t7gp9vZY3{>6;`1Sk&3SCRPeyEQ8oP#l{d(cQk@ zyskiAs!Aq;8s>F`KLALF9Xvv;=MacyKh!&p3ZNN+0}Z6d51tev=oAOWosAO;)bXNI9H=#l zV|fta3MdXNOmQ&ga!7wuk*cmezeaH=Ual6}P18G}8giEjerjkvJd#ffrLztavzPoT zeZfFi@G3hrf9w$$L<|IwUuk+LYl~>rL6%}M36rd+?BCYklgc=1At<%NQhZsdamsmfH!WeLG3jRyfe`UKHK-@OefXdYf9-EF+VF zUM{A)oxagPj+{Au#&gdef6E0RhfQK(SQ$Kv7+f@I)opH{6J+6lj0;Uw_pq(^#vg>; zPHp&__DrQJ;C4E!uv<#8-TMygb}C-s?pJD=p}C#P3WEq4Y#f|t=@f@jO{Y=m2_}14 zijvLo?|pUX&B32-~Hwo}_g#DUzY<6J$VoRI*gkwf>h`+~de zYP$O-Y(brYThLTh=PqMfCcVxepVXnfw|;K9)5bo7q4bdt@8dpTcA9A26JT=ugaIse zS|H>)?YX)pb~;qlV;iv-7CY6K1~L+W*a<1Whkq0CE#~Dw&8t3|*vVqK3mSO|C=R(; znBu_SCtZHSFVils=SibD$|48{YR+?TUo7g3@Z5a_GSR0fs48+GZ*L_qB7K|rN5GQ) zreDXI`>Z`NU+pQ}XBatvF#-s~fEIaRT!2Ts4Nf%lRtbPaLvpp|hSTUF;(!8qkZp6t zE$T<+HgmHrgCyTuBJFPmNubf7UkMrw&&xDHqoFBBNp3IPXy|787j=OGPt?~T;mL_ zMtYM#>@-*OTG0~S>Qr*9W0Ed*()Z${E~vdT^m;e`l!(1Ov`0EBv~&_%r*ea+D@=^l zOWTDkk zGdQLo^3J5^QW^DH581qJUaM0(~@FO&E)NuTF%Rg%buAL zq?SBmpDiT3GM_CfpA4HVCdgHt%Khl-GlOqDKBJKP)!2W!uuh{O|3RC{{h0?n<{ad* zR|jvA%j?)}PHgYJUQkrgAKOZh}Kb5uj99~S1qKLi*;&tCUcb5$wqm2*KNE} zsM_#Z%ijBmnvBxNXPbHp&!#t^MR`=~(Kc=B7bI-L)tiKEIMoe#92UFG_&v9Fo9MLr z_Uth%T70qh(Dw)32K+9ZuZWBvTU9FBkgbYu51*PGzz~!b29MWqJ$micApYo$=iuHi zG6R>!$>-C&nN=zhFi5?xqoFP*{l>z#)cK9$IH-OTcOLya725wdIK!VR@}Da5pDObI z16AZ-0|7_i6*ryJ$t>g1xPP7~(o=evvzZ{Iw+YD`Ms(l7KMF@1Qd#y+8Hg>D zu%DrAzlD_@Cs;>>NjJM7TXcVWoEWOX2r_yj`^e?1!D%8NW#*ows(!;r&B z-%hvbRL7O&ULton-s~JB$HwCTa(KRXd^DVIZmWboesL_?NQL!vV8B(DOG7}PXJCeEH!I$4}F^z#En*-@YO1-YBzU>}q2nks+xksW&oe-Fpq1pR$kby@#?t*4n9|pZzxU(J>-JUO@&kD^>raQQ|7vP-VCP zS&Xm_V`HnXe&E_f%z8U|fF)BvD+-m%t*GVg0cUi{M%Je(`|7FeQfCNmX$s_D^)zY2o+fB+Jt8E|4rrQs#6q8yKY%q&`Qt}=e+w^H zy$e`p_2c$m*$%YuavBIPlal@^yiAP?GkamQ0+*NL!hOzGq33DkWt>YGC@;^gmX~=Y zH8R%9%k4EBM1~i*3xq|#7C!&=XW0sN|D&Gi3yT;I8-UK;DijKz^iMwD30Wbt^|9W; zR~~NWZ^L1BXb2sA#UWRrO}0XEWp1{75opiIvo&b?rTQ(dBG6JOt&*pBJnA z`&awRVrzybVc5`g$6(FSRrLEyTH)I(-dRshy6E( zrkKJCP9NKQ7nV@|G(!`^iD-+!=rc4!lhp5qCg>V4G*xNDIFHBSZbH#!@v%4K6Pn{+ z3T@c26kGF3a!Q}wnu65QKq!$I4O5YrK*WzGcH_7^=O+^I%@SoN@54v^k5L7wK9bv` z{%THG_w%Ta532=7eZHh@s(zCCg`|%a2_2PQk7?-!NpRJ#j~i`vd-*P28f|)zEqPWe zB`7U<(Lcqd{_+>lZNSsI4KL!_{nxq;q-YR*1-yfunb@*c3e#G*q0ap-gE`!7kommY zZMZuf^PxEnG#OY;1Qw)N97@xtE7SN+rTQQ;fSxIere~5Hh)oDhDTz+UB3uq2m~>>! z>hi)jS0(dn3mN6ZSN&(;s1K!WR7e9~L+=B3ejJ=`_y*DqqZvM-DSPv?4xCMcJ_}6K z!pj)Z9PcCS^ZgM9Ye)U{v~I(+yodg>0(EPZfE}&8Yy-;6YPtF?LZ*#yd0DH)3Bq5B zY)K1QK4x_)GnRJMj}QCRZRpmp0kA_xOC~dLGZC{KX>KNQnwzPlB>|^U0NhMJvXoZc zOzDBOr|xb&l5MOWq{IKWZbPeR3c-fSD=inC^f_rK{cdJRJ~eVMVO@Jmw#k~CX=1gy zTs$401y`3x^XO`(FTYinlXFV4yE5%=M}g|HR<@FwMltgsTwNBJ!5>RVhpWrh1)#dT z5w0#5(~kO7dUm;#r#erA8T|xA8z>n0({QvQ7F_kMayC~BNztMWqIK{5N{H!8;VA2zMJCLARl&BB8tZK3&fwl^+bc4S{gCA+Z(i zHU#|EZHQg7GZhS0nl9414fU3w+mL;U)@>kFe_|up-CpZ9U~aNdovXcnb{mK_4+wcA zdba`R*2e)2Tw3imjI4DVnghgboPl5ip_m{_o@-p+j8b6{tp zN|{@dt3v5|rhrQtTyxJi+OF!ET4`5(Ur=mtZ3wq05JgA2UtBFV@LV*BS9*4TPOyg^ z5-c?R28s;^MKa*3k82J{Y#Btu#fA+EyUAgz#fE?t?wp#Z73*q2u_4eN3$FTLN|~VZ z4#daJ7U&ZuwZ>zuga@=@gS21QAougc_CfTsDfXQw?ACaPG`QH%Ti84Wcn7D}bGJ(f zJ;mUtFMB$p%e51e*!ghcFgWTj37CGU0qwLL3B6Mw=i}>;~Mbb)GZv*{gCEnnie%BD{K#Bj3}N6=(6LMi)hgnr@5K# zq>(uxWw_Yj1Q#0?9`)7q?BMN8d_oGQ6&v!V%&@?IPB|N)aFx~;ln;AlXlqeWg+)^zM&NxFtlO=sr;4`ZX6L5*%_@^3Mq6&oh{3u$&H8`#ct0oa)i7xm%ymzuvB%=7J+ zLti^u>I6|S54*(R_;Nt|>#Sgw@=1YRtis)41J$8iEw!%(9Q4*#WiK*82LSIt8JG+h zYHVQVl5%|pcn7t{E<3LB+SeaEckAJg1KvR*9v$5}_yh0`*cV@pR;w|7iSc7M zIjfWUmqD&Utx&Caypfh`;L%gsr7~(XZ~vM@xS|$K1U09j3A&m|ho)w-@Pcy=OWM#=SIrBka?unyAX(S2o4kU-UwxKyVyxf@I<#?gnk=!%n z@*wxh8`CmpGuyeaojl^IoDEb`KFHiLE`;l2l=z!``!)V zvvu#kbvXB)n_KeGGZ=c$xR0WGX`U&C@}2r##8c0)n1V`~Uy|VAJ-Tq}8Kp^LUhwgP zgQL?3@#_kLki*{dzsiR*(v;j6fb^fU?|Ie*1|2gXa4?gPa{4bb? Bo`L`X diff --git a/ext/picotcp/docs/wiki_images/picoTCP_logo.png b/ext/picotcp/docs/wiki_images/picoTCP_logo.png deleted file mode 100644 index 577678f27dfacea38faf57a79dc0216818855ce3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65949 zcmZsD1z3}9`#uILpdcMix|tvh2}Mv^2}Qc421qlBk%}NOx<@JqDAL`iGz^dsq?OoE z1Y~so@A1BV@B97!-|oZ1gRwo&eP4NA=XE`VK2%q_M9M@;L_~Dyp0fNSA|hfK5z#4^ z3+KQ)#gtO@;J;IdM@q7%?|krW13!>BE9)bOi0G*Z|4vzF4uY=`F+Nq$d#dRKf9hf8 zYDJ`GYvJmI06(!lfWvJqto)a6xDXK?N8gjbtK~WVEB(BY;pk>Zv4u6ogv+?7L+pzG zw&QrNz|`E#?ZK(sLk}+76fs-Hat~RmTUFuAvy9gQqXU1Nd~Hu|w3jNOl!a0>Y-fDf zok4J2f82n4@M5MHcZEb>d39=kMQ-&yVudpBC3q!jE!W~QsKMq=ULTz0H=5;FUUJ=$ zlao{V{Zhu{&u>^^37vr$dBWQp|Mm8}RQ0D{qe=_on70dN78(#XrYQ z(CA`zQA)xd*32Np`Ngp~Z1s?VJpAamHnvjz zBOjxqD_s*qpN>t2c_TY#CV2f#c$}7Y+~&PiuQ^hogV@&UeEK+IWs)jGSUR^40}iSw zdODnnCax8+Q*m6EW(~5!R`N5w<>9{|0%S1D2P;m%!PQ|DcmCdVG%L-^)|%Pq9o2iN z9XFS3&r(iKR}_=HwubUk8u8FWF13Isx6WRh;2opMaV+<-fAK26GJt>lY{CsPeuv1g zZdfR$Nj5ICzgc&T&iAU{?alGh?T4$?!h4?gFCGvNBC=0Ne;6qKt50PcC*t$dtVXu67Q zmhC+~8mQytl!K}B^G&|G3hpa(qu&^aq6s?xV;9O=NPXU-$4GrDN{Yma5Jr`h)^l8f z;u-OY&?J7Ft3BREc8!_ou0}`D=72S1;skMe#Z=x2OdT=_4fo(Lq2gjX9J33~{ z4dPUkNwa#VPA-2g0X+n6aXtQ3hP&?vtNNj(LBAEmS3j}gv$yxsrIWVQB!iS*HJ>8F z-FH!*)EH#<(}2*)ocW-dKN4oD71&zX;?SpE5h{Mq&tQbTEKxL!E-~pgWq8_P`mb5M ztOAcxN?F4~(>GD~#Eb@aYnN;reo~aA0^3^FulJ^%h>`P1hdy~0>)OK1w|c25I2}nk z5B%UMSC(c@r{+&87drP@phfhn*h)>LZQ!T6Ru+y5(W- z=5H%+|2{Owti0rkBOdR=$&*)vV7V5d;9B-8zC*S8SGmq^8WKN~DMW(GOq6e}Cnart z8_2X?;w<*-UTI(4EZ@S|X@3{x&j7bX4oB?*-w?_3~AwoL#bQW`7j+aoXbR+Mig7qJ7DbPkd2~`}!Gpv36z4uPV zqNB;c;IZb$%rN9aXd}ML%taZ>iwYsZA7w6loid@Pnme&U;EmC&BCthtR;xvk+!fbc zueU)H)V8YWpzadpppUA_lYl0c4eK{a@_VpezeJPP zI}q~Gs5 zw|mH(MT>m;-0zh(96xbE?KGvyIK2e-B_c?P;EP~yofx*jQ8K6loscUHx9(M(mg}47 zj`J(qVIy&|P&&36f;fUOst2WWiwonCaSA12E#`Taj`#E?H5sU!g8zLr5o-DYB9Zme z-@_)X3fUVg^nc+*4FqRjtf@69e|R~C_q3z3jYfBgyFKG=R=pb$@29pXfYk{_GYCJUkp|rct=m1R3b$1-q;KNn;IeS;m&20`=}}g_pV}yg{=U_TD}gUuFR+4} zDNh=VbGp_>t6svAS#n##%_+lllyJg=PPA84KFy92zH(jFl6w$y>OZ#`%bYFQk<&+g z{WOsLR-GK|9bMDeZ2jb#+EJ>`IH!G3&@Aa6k0tC27!m`W2uzQyNC#X!W~_b-bk8tPc3f2flgjsD$dX2=p| zgR#Nlwjr7W{3CQPTX_f{Jo7kIGPmD%gM?ref9c?kYc~e$(oi8)qLmUI(jJHj#HgBh z9=W=_!qb&D)|mK^fDe9F@pJg)cSFfG>%VUJ0DkVpZ0szzu#0|yh%0}HYS9M9`6-_! z6Q$OOE7f#Ae&i@>4dInBv%VjV1~vf|-E}h3FaK(&CnOCNd5+%j#$2ba8}ULs+4bB9D@4rR(b&NG;%9E|ZtB_VRFUNC3)$%Z+T5wC zl6zR`Q&471!p`q_pZq%sTCyPseu=C%m-v75MG; zXcx32B6CyMnNq%hBLD>eWv5mM1=Ntc-q)plw9O}wD3(~(KSJQ7efunmRc|2w-k5R3rjm3 z`A9;K`9eb|x@UG9e2zRgn-jKIlZrQg%|?G-Sn4;VqUu@jE=SD#Mds8qX%|fIqzaYt zqsmq!>Aw_S?|8=TBMKzgr9qJB(}%lzZ13M2q^)0m$*4+&lq{)q+>CDinZM|TPCoy) zv){pYVieb&EZ@|4ILV8p(4`A*H5#L6Q(=$SjdxHnN!jaL#30A8mS{oAQQC^jFYGx;$=YZE za2@~DJNt4r+A|80H$gfYvf4Ev)4AQc<0l>1Mgln<_P{byWR zj!ps1$idw=DXpgRlwlR}w#L5f!r7D+Q&WV{b`pSzl&|rRw-)AhVj}QjoDGYJb&}Yc zHxiui4$^0>Ne@Ncl5!||ZXqWR`2fT;Ps^YtrgYK2m%3wrPhLuMke6RSdh<=TDds>` z8?8Ugs>9PwPuxbiCf(H!Li%{@jVvw4IX`A`>D7cAJQdLS&>E#xKB0LVj%M{=a_ zQ8K#k>vE`c)bqf{cit4-7hYYVM5jlim0{5KYHS~|YkQtL@_}%x)mLexcaQP~I!*cB)fr8jFdj0trcZXqi2AoJSFAes@Yyb$85JW~ z76C?rI0-<3Xqc?Idjo&cx_6m9zZ0!7Fin>5;CtpU&T01j{pvO~cHWNHy7on5#Avk5 z*`?OSFrAn$nv;APwm2ipdB-$C7gbZq5nZbb-Q)CYN9Y?L3@CEoNTF$=Q=Zq ztLiYy17Y>F6VqyG*0`f>RWHFL^jd!e`j!(KiBHKOe3`ILFcY{OKx9Lr?7(?7vh_Z` zdk2-A>f1ASxwlQ@6|F;-VbigPFgcM3!iKkiK67pp zrlO`Uj&p-8EWiI>@|0Mkq!OnMZd>VgN3@++axFdJHR51ymjE!I?Kt35rB8Wn+cPau z8;hq?e+vLW-hYYU0!r?anY$KuUNhdCE?D8R1#sd^l0wH1Y~>-sh)a`UVmGR*Y2;fM z{@2YzO84U-)qoqa^&cR7+%X=8*PNci>FJQI|fks2qwBOGm{AD&(b&u0B7p ztpBzxId!uadV1Aeld^1FG0DpL^fMnB04P7RFU;AbQ!7^Y=Eb{rSiJ9F>L(aL=YJUh z_W&i`%>0F}S#CtOh_1axHJafJ5!x0?Ol+>Dp&a;r1TEf?q|gl6z4AXK4>2$sX3bA@ zPp;SDCVRtWHlXp9yZ!M+BFo&hP6RgaCiQ4*A&Ty*7bCFSlXU{MfZD)Mh(${c<%3u5 zFKU0}9hg8LEG!ENpCb|(s#st5&^lXn578*LM|_X)$&*C@<={my7;;9GT4eY94N0Vf zx=A+mAq6X}H~Tv0G;|-~fqXBCXe=}C-8T3i)+(trx9LVF2`@?@cvyo%TJ-9na5yNN zM3dU=)Bk6Xkg(D{ zPuucE{?KF|F^R@XPUseGRcI>VcrfyHX(+Q^)7a#u%fD2jss&O5c!5j7sg$$$da9F| zUgu=a&7k`eDuqnP0`smET(174%Id=7H z;8^@D!|l}Ex!!>*ISj`|@dz0A(N7$@GOt1Q9y}EsV~&qH4#mZ$X*QG8J(ZlPDDLq; z4o~xE*;q_WU9dBuzIaY4D~j4GZKx=I&J_j8jOs*8C;7Ny<~evVNz*iH z&mH*3*3XyzMz|F{waKKoSwV6Bc4GC9IzQq)8iHNe033D>8W(&yJ{9q>9$Jk8?m zK=bX(kV9gV>Z&)OFa+k%srpQG-ON>k8N#?>!*Zdf+%ItnqfAy~ueqSG!<5Nkp;Bag zi^|!0@M-1?_)dBl+D}(zcutx}t=}ygkUCC@?s_IAPFrIzo!xo6-84p_^HTaU>&OZU zeQ2V_A|je%P$1%}S|a4vVr;EAL@k)nPzea>wh&ypo5_ zq!zHJzmskA7$ zD_w2|qdlWVo3|WxrSrs0GQ^KR1;ktNwS$T(4JYA}|E@~|-9wo`!U~&{*CO!L7UfG@DEZ1_voVuQQi05^O@#sXprO4V$)C=a(#u`J!nsYkKW_5QuNyZO$kc zag-NQYSlcn&Gm`ShpV^x((yI@k2+*jFwfE`pq%|yM`<@RMZ9p-%~2_ulKM{s*BVmN zlL{Sot&hYdtI11gdfc9T5iZ>;n4C84UOtllY{3}pB6Tb1OsL`hp!dP zG&~OOH`_g%B>`$|bknoT9H4f&U(V08U67y;q4UNCwi;e1_-Lemi`;BtRa*1JwJai(=<7qg$5s1f=}0CU=U)p?53C0jm&7{TRs(h zq%D8A=~s$)FLnN~D>MB^++j`PeyMfZE*V;C7a`S-o{5VRmLBmm)O(88!;ZrY7R2gu zy~_N0`F=9UfkOQO+~+Rstgt|@C{08+^vUHPCoyMx*WW@z`IiVHl;odaitePZv!sDC zxh{{BAdk}(SI!iBqjBA;>$Ub*;LhFI4ZK*?yeAn$q*3Zv`E9`o?6aO+;;VZ+!Arpg z>iXCq2l$uYiGl(E+IQE5FFi+ZZdc!OT<;{l7Gfa3r#zzGl63~_> zDC-Wq>~So8l_Di(BzsBaW`zd>r@0IkVSRJm2z_4PaxKU!%j8YD{db3pHLwRe<*;?V zUzg<2yJH7w1vZ@Nr#cL^G7ROS(Rr9SkA0)64l9;I^RE8WaoOLsXpCaJde%{UJ->J) zaB975#VY%{{84Tn3jGtZnIuJw6>jYrmsSeIAt1Y+%ao7N5&JI znNS%QAoy?Qb##-huiU9x`QE+Qau3eLc&am?52tK;20b=3vq!(nKvv_hpYQ=w$z!## z@Q^YN9hEySVF*oB@nxP^JybWO_1FJ^OOg*!W!V!7+?e(SI?ri%6OuzjJjx0S9@q(N z+eQ|uBJILjzioft79c?#D;%Ez8#}3dPQ;tWPhhUN8!+(>@*fIkc!c29y(DlRw^oe@ zVZ{x1W|k03QHIcMQvzivNpp5`y!vzzCTMc>{t@Sz6yyD!wC^r96nW9D4XPQpj(&Me zjBL={XCg04=}*6{{pF0{#1j*W`2Ewf0Q)h7T(nLP<->ki(js2Zy%4H0a11>ANUI{$ za9)~)-|ioUb4Oq{ek4YnE#GV_mq?$CtNAgHyXw$t+x*eKdtLQi!v2mVFnFn9hAh*?ik0%D=YLJnmV*anQ508@V=8`fSaK1=uqt9`@khBF;@A98*M zN%rKuQj(cPj4=~%t`y5tkSLl}JhlsjB+@jyG>w6pm*bEbnA!$usFJz4QMR+ca|L&g z4?qNr%4a(<@o}cfTQ#xCH)uuJ+r@@aG@_7rdR4Sp2OG-BDVTb@*TU`QmopDLfCJr~?fgdk@ zXY|>+rbiXk=2{Dx!L66UqJB%B{^V7n+#9a^Q57!_+Z`n5 z5()df4V2=-OM+t2>OQ;%7#~*}iEV*@AQd=t|MK89Tc_=MST}Co`{kFQTdPZHuYwQ8 z&|m5tYl#Vf;d+g8e3~f=p7*tkEE@d+b7cz8hm?N1uzuSA`}a1zjNMgr_uQMoSfstm z?T|rGP@W2D?aYd{nZE(;jYYc|wMjvb!cN4pnbST6FHAKozq@6ZoeVn0e=S1s)Nhdr z+1rW2Aw>-JhcAwj;m7i4Yo}*R!u@3kpv|;_e7PFw=*vUD{k-A61DY=i=ij~l!OZ04 zX$#LI6%S|5_h~}M&$OOlRDZg>qi4BhOJ&T(T^QFf2U@r1$tGHR2_Y9P0kyqcjHZ2E z*!1~AXxG2Mp2#|+x+B{zbK%JX?65ChT|mZry!M8d@XCOA?)|5fme@A7?WNdf0toiv zgiZy&m+J@0Zs>PQwz|ZVXm@o!ihM4y>wfgEIq0Y5Q`CYR#>?_TkF4Od z2z6m0(ols(Z}8sZLq@7{q+f~)vmRXnn&R%?K?VS>P7LBJU9jVBY=iU6t=psI8r1a+ zncqFS$Xt9;N>`3gfk-6)bGyB~_iRWkGYB%$uIhlcEq&AIAR$<4M&oBvC%0*ZrHbNO z?!9~w(Ae#>=Y%yk(fWMYRN^j+?|vJ%fp{RGyhTeniLD)_aKXsrX0887ftAD(E82;v z=~j($+|@F1$C4M_CySAMXmgYATc44@{^BwqSs%c=UHq*-r`HBpL9p^qdQ>GxST4aI z*tS!hJ_ns*>ySwo`34hp4Nq0svFhV%!|BwdLZ_7PSEk=BSW~5xZmxFu~6`pYqpXY^D{9& z6#a$YjIg^~JGw6>#`6`OL!&=gP|+PbTTVLwu5A;)2HN2#XRPXe8 z3pRXG2+O_iX{0x(wyEgf*N^`6qvtL zn6mkEtK;MV5@%nS&(EG4_z*LcTad)pKj8Wc``eokz6k5YsP9hS;_2CA>XFQ(&cYj+ zm41lrjLY!_+}aJR+#du3-|(VG>-$)sZpqv(m0t zlH9J*=SXB%Pj6arzPY%!)NW#-KlqGe>dg#fXy_Pn>}RD{e&zZS#X@Oph=`_Rzc+re zsyDQ(_1v~N$|liQDi`_+vEbQVJCU~3`8K+G*F>p~P|mE^*++F{9`|&X`aGJBOxlOF zEtT|j1L%jnS-7-d=dRXMDX`l$mw&{~i5a}=m{_>UjIx5f0iuv4y-3BOKbXvQ-F(ik zq(rUZ(n;F+Iq8#{mTAnT#;s@*+*ba_xlStb%jh4y_mBCMR$qy%?-uWiscoh9+b;d~ zj9p@fh^+t814saIbtFq3y45n*u8~k~ZhrsB=T6^h0)FI&+Zgj^T}9^J)8(pHO8y=X zs~hf(ZoYqddpWFWpS#vb+PzSzdXiy7Z+h89PnyzstZ5lx>mSpx1(VLhMz3n~J59_l zYb4q>oK+}>_Kpbc?A#MYcTx4?x-W2jqPha%>tRQ?WzXa|fU*anr*lrK%BkEr!2;Qa zL@^k%ECb-Yh?wwW@7SW1bZm3=-$qodVQe(YYgmRL8YxS|bX{|o=~Pr4B0*)H8WdqwR76vynX|B}oz%zXZ&pDtFNcGDs&#EggE@9RnhQsYytu3*tL;ePM6KkUu>?`$MBDO} zgyV0Dkit9k4YuV+x?QFcmO6iT&aLL%HTI8tj(g^Dc5=@cxe`9+XWdRIjdQ)}Wz?Uu z%iLX>mnSE62hN>#AuME-|J`LVAtpPLksbgvNEGfqXW-f{9w@l5jJH|KJfvlF0h3gJ zEoCZn=o2iqQ*~_kCK`GvB3uz)FA~4F7{kn;)$@8eae_MLxJjbJY;!-&Ah*A$k-vJb z)~J3n$SC+rw+39&-65ktqx8NbE)sx#zf9prt;Qi~RzJG&Ah_MI%;ga{bd>I+Qg~I4 zu^!{>SPB_^x3CMTVmaq_SXZ+ZMds#|dBND8INd-^&||$8kvx-X=%si{FG20$gHKd>Y(rZIzNhWjSRm8{1IvickKZOz}q4*%yV;MM={A_T*3-F@QTMl9q55^t-{Hsj5b~be&H6MaWooJ`QeO6f4tAvteV( z%P>o}`S(x~>|1y8G6Mb-!Kv4f!%da~soy$h3CDM$L)gW*d1JbJCV+oHeEx5duGOO38^QU*V%)zNVoY#koZiMbycDeK6T^s(QJm!)*6D z&~7&d609BN@sY(u{rRX9rl+r9OQJ$3w|h4N^|^C*E#gkqGHtE@djJw=)+U)@iC-C@ z5h?xkcRk?f2Q0^H@+>e=4#r63Rj<=)Vf`iNU;lzGsSqO2S}vH3GMQu*E4LJtGj|R{ z0^&cs2|)PJmf0KZN`+Q-kF?+gLKCFyv#$RX>5{*!avN-9-Yo68NhdAam6CSKaSCha z&(n1w*1}oWEpz<2guL$;j%P?H*!G2W$LIqv#sj-ezI=WNan%L&+v;8WlB%l~!lY`M z3&rJ@J-E^U>h!zD&D@a|haQpGEy><16B$B=_{qI1MrzXf?f0wSG;;OZrncda4X(b}`b1?MTX~#qDL|Y@ zGt8Bm&PKg`fq}5vZ&V2T1x-wlXRYgkNuA`h&{DymEUH6uDH?l9Ny#bXM<@*fo6(#!ZMcj@Y`bXY>DzX zf*4@K8)*Hnyma|ZWM~BWH-ws1YQv?_TYp+C1YnqZA6D(|d3B^qQwYzVF$(MH8F?^o z^#J{AZBd+OKB!t{-|f10_ua%Na56PP_u2H=rpqEQq$RxQ_U-f`gE=k{$@>rc-qC@O zA#C)NQ6+NfCyrOHe8fLIO!Y7X#L>L2X%BqEUIR$Y$N9>OYHTeJ7z9X`ag0S z)H4iVFlbXK!A?j%JF%_Vne4rmus6|yZ{GY86%i9sLm*oJ4s_(+XvR1lC6L(X=wtc6 z#&LJq4*Pk)gZi^)G8PYi3{>92OQF3nbSVRi7`}OgUeiT1dPig^&#t=5qJBvAF6^P- z`N^s;1P;^4nbAkRv&=ULHJ%(Jcr~JPp6kqpMMlAfQ=Tfz&5Gb`*`c&}gtls*?Zl6P z&A^bOU<~9X)!Tb-&|EN;)GuD>jxdhdDFSL^G$oar?F9oMu+=1e_Hv%K1_|iVEobjP zGXA@Z@sgyMtT7}?!Gd|Cwjwyz{%Whxx!Zewk&z_ST8NXUpJ@D%@o`L8@l(X{DAMwXBH&U$X54@%AJ(d{B&fU4@^7*v2D^HIY zk{$aLYUjU#o*8h)J6mxNHskIkU=}>>FVbbjN&;JWR?G6Z)JDfkvITb#TOy&wKvn$@ zDFZ5|*KeDax(n786CZF{G($`tp9?yozja$1ajF}{-BWGUB^elZ|QJXrdP{-0ZmxrC|s&yU4mH1o+YJ`!? zW>>hskYvw>H-=#fC}qR%%mC^^VoO(fvggnW?uC4y1;)rc&rNXu@vvv22vEzZ#cZgu z6?ri`Td5CkRtUuIeYz!Z*bLxy?v|N-q4*UrYsO4XOq|%`dUd38LxSdz#OrC~q=n=< zv5_SjHsT{?V*kAy5j1MrTl%0+c|m$XS+}+rh5SJYOI-UV^rftP(3c>#+>Bew;jxFq zAMC!O*+k-{Y%dQD5bFNO^(K=^lWG3Q`>M2PF3P+3+x0;IUm__(fZB5ahqDeJh)4={c2rySb)c^2^xV=c52JXnDKA z{sO4}r1RE@{k1moS`6$;^#oNm{St6hsRx1+x$jKonlE3dv4^Zp{}{T)LTIgtqQE$m z$yPsi!jVHP21*+Gl#ndL<2pfemDi5$idOv7P9rqq`(zX6I)@kk^x{B!JK~v(=I1y@ zm&L@1M@ye3TxuN*|%~6YBkVmph{ghpa>NL<6#6{Z(Iez2umyLO(t3Tdt}qj=P{+Y%BnFR&wYuc0?8RRy9$&wlADeK|lqIR8!XV$B)%}+>*<5 zxO>Eqkx1vSn``l1k&?*v;><2^u;vF!zT}6E1Z}||Qc<#4b$v)?hb?&01Sxb|wi1ED zl?t7$lA>Tc1+R20e8(Qw#@Foh{fY3B>coYA7m*J*M6`v^>nh$E-F#!hvaWhkXZ#xR zf@M{Bk)G;mTHg3E9t;>W9K&z*(wDjD1|4n|vV)9i=<iV2CJCiUpwfsiW2l!bACICl@PSb|FuyRj>B>_9D_pxzo*Lhi?@x z{c^L}CWJC3!Dq6w4=S%JKkb}R@}l@n%1OlaTz0#0@@+Lx^o zC;joi_lIO=M70NzA{oPVFN$XC zb+O_XgpD4e`9?SFT(AB}T}PB%l!?MxS>qp3v9N66znbj}``@#C`o&Y)1NXJi&1mvO zwGU5KC{CJIcR|oy7REGG`vT*w69kw)BmwdWb{779L5QD!VwOillIj-sqgAP-<(Gfl zR~Z(J`4!Rmv=qbS&JN?h8Nku#zCNNhpCxCKq(4)iz)xw+6_ z<#n1_qJdxj=knVU6K}e)1C{dy2+-Z*Eg2dt+88gi%fnit`C-`_=pTIPRH-4I>l60b zNz~seMUW(?Br{9ejicoI?jNT!+FAES>O80>5PD3ZzfzMh{G^{K&GGKOQ;sgQC)>Ju zG8iU5sXflAx$-PhvlW}7OBEe2X=i3!dj zl<`Syt*R_!r&=ni$Yh-DE!_9uEZmfTT#IvSZFX;6V2k*VkAUt(CB`xaZP$O{+Y94@ z{^gN({A$BzLoxWzbDvj0h^LSwe=pthMtSm-oz>A9MDP6Egw;NZaXn?GWohszM4ILE zvHKE2Q3&?|CunkO2t;Q#0?O0ql=f8nlu@TwRy0T|L(xmm@~66C0k^Yy$Yx)qnB zZOsJ)4ngZ}{re_=qr2UCB?OvFBzrZXNs?i>xWx#zuR`k3G{A?I@}J+gr}$|*3Pd51W|fq9Qozf}|9KS*(NBiTx8`tBu6>N9TdR&O z`Q5YpwHpz-tz9UWN_4tBc$WLFK-C2U2$hg&XVV`z6TlgbehYWJqu_wl_~9`gxdWKR zSvliOlw*`t!KmX@*U~g&lVk2o+fsbrOH6ohMV0Rh&8A+!CEhp$QIZw|i)*WNM50EE z7@K^~qC_)?ekx{CsH^LEk>q{9auoD@YFtAv*{eqaB=r!?MY3YFh~~6T*34az9#y2Y zzSXcac(CQ`C$F{VU|7`5MNdj&kTU>($c}Hkh0MSoxsZBf$(wCaqrcmHWI@ijyxyny zm;Q4w^ObWur)3rgoZ5ryP8~Xq!c#O#0!E|fD(3@i*NUIqp0v#EH%q@h(Mp5ZTzKB& zjsb%bFC^i3z4{8%zTf5YFmJc&!7PnRdo;It2N-U5jawrW?pEMJ|;^9j4ZDnmvgdb@Fh+(N^oMq zb3m@U%vZRKp=wD^kr~Z9(s_v4r=Q|EI9I%y zOR6(}Q#taZ5E#~()I9{#5lh0^IrnAIjLtEmR{NK*NwvSdK1jOTEor?FuzkPgX0yAv zUVflfo~OGm+22|EZFGCQlIbt}N(2Pbes((OQ~_{J-0)&9PwR2hONG+);6N${x`ZQFuiyojo5*V1ZgmitKiPtG@xXvjpJ#6t`ux;(N zB9_+xhkV;^YY<5aINifr ztZDbnqJO7z;-dU?#!@Y}K%-?{|5qz!_}kG3LWEckaYZvyQP*4!WfTe2e1u|Z3w!*q z^-$#w5JsQ>k%(0B~H_f-<A2VRmOaU(axE+70kvK!E?)@e)=ADEO+xIG8Cw>->b76LV z4qP2mTXi?+9E9}y^HeM`Pu3uYt$%tdSFK%;u2(Z~U<(Z)JQBpFr{f-TnU5pLLdpiY;m#6gF$qS-r` z{5I?~W_|0D(CIgW$1u=K2D5WjUaY!QL?;2 zp+L}AbyLO{b za&b%oMcD~Ihj3ZV{Z~oP33c@jCcfV_Tl`w{=!rd0fg*fbyZ$49pLVOXH%`V&{_19? zJ;gI2$-gzl;pV=$`W-0<(df2X{Qq0oQPo2f^IR1fb&ObQn{$pvOLy#eAj=Dazmz%! zVCFkZ0K*}IH?9=5>(q9dR=yCVA`SbH$PU=AXe;Wzwc)> zZD}JY8vSy0jvg5y*DTN?ivHndbNtaLtYz{`MM#{%v6oc~BDxqwJ`($0$H*p;(9t@E%nr6o@ z92{4%3bRwT6X=Y;c_~@=tlX4sV8}vxt^3m5Y>wUB1=mxocGoO(OFfOp`+N1oUOBC0 zK5Kc2`s@km7n~RkV4nK@_9vsXI;?ssR9a@WcBj~8zO0nCcfld4Kil`OsLBf-YbyH| zU7g!W!yJ`Wvco}uy(v7`1;)>QaiG(x)alzSxsW6pid#rKzLOR4pKPLh8ZCM9JRG_6 zYtmv^%WthOHf?rx3?f61pU-|ivU)1|l_+Kquw{Y!zi&xdqL&5fA{4t-{TyysL&oWW zKi`)2U^;9&9reJEJkwBfj*J+Le7^z@4d_quk~7>UZ=9pNCbl6#*bP(tn=?WzA5X^# z#3hNLBHAd;gdC}7_(EF66Cea=@h8iI`3rGkx*py!T{Y;H2ngx`l9)46`LUuxfDLwO zszWzC^4!w%{Xx5GN3{f+QOlOO&&=u67_q0}XB@9Yt+`~%9fPqljNau1F$4SXE~g;hlgsas*Hp>}F$>F51X89U zq_am^)Xm3MNy`L(kPx*DjR@hwZ}B1h4$VO|V^#K#>iz}-u<+-Vyaum2zVb>VuZ;3G znNgzAIcnkpy*_pQAAR-1C23e(At_0ybp~eNrO#rt=U(V$_xDp6S5MBm=}{10G>P&| zOk2fIiZKHVMTBsDo*gGgaH^`N6kR+=+{ADOkU*hT(1;8CPN79^UHdxKeEipUXXcR( z7PhEl(@9Pf0^KlN8CuP`|9=6)t!wxI@5BMS`ga$Kp-X;%_r7JB``iMZL)-UTQZ)vh z-(4xUZbsgA4?bRrRO~l2iP8XFW?^5Fy#pUB_&5X7ajFd`Er)x(hyV1GfcPPgNNA`8 z%Q-LSHFs}M=u_U0tk5MwOTM+VZ*uNVPFytl=5|g0_o#hH#(U3w?>APe2Ojs_dwdPA z&3JgZ#3>7qqD;Hiae1T@tvB9@{a@6fj_N2P4v+l(h4lq+2Gtt+PmBTP^Cu;RCLynmC}yMHyF3+CvLrN%$baa` zw;sF5yc^c0&Kj?&bJfs0IO|Ihs|I)F%#q5Jzt2AV!gac#xx~chn-4EZ*GwF)DNJk) z`zgAnsYK1l_#vyJ*};Fv>%mSi?;VT@PsL!$)Wx!+FMyc#225PBRcBj0QBUL(i4(Bx zk@jUk@G{TVJwAc2g55sqpc72@s$b~$YU-4M^-JfzQbPg4C4)VoO?_?h_fs&Tee(fa zKqj1f%$%v9-Vs>v(GNQMGwF5`Scf*q9Iss!ff2LA$VdeVm=LgG(mciJADqQKTjChD z^?}U_yGHjVgKW)Y$)7?Uj_DCVCi9ti%3A$#SD0n)XogAe>UmIENd{W1WdK4lOVs>{ z!aDFuWkqzC?RWXpb}DiN_K^r33Rvd99+|+bb1@ia7jw+O+Gs#`(eP^3aSKF*1x#k% zjcmcb`e@OcP}b;v?Yys_*}P>=lIk|2;hWHGM5B5kn|Y}bf$Ngga?Tehp2~Y4Fa}ERu(lW{umm-4xc39r1vh+LlLHXJe&0{TfgL=XhH z9#}|n`pI^BqS;~V%$7Rgw@cYhT*f9)7kj-srm1BDVJ%kBA+mvj6MnvE&7 zV8U-Qk`88-+i$f`4IJp~i@i;}=d=xYNT*8#rXm;go$T3rl=rehZ-r6tYl}DeITMu$ zggkZP?r*MhIs#(dS20S70;;~SzbsflE&l5G-@3fVPM8sug||CgEYOSqKx8*y8f|h3 zZTl7jNl3LazOC&TJRkyNs>E>@g9rSMs6s=T?crr6`8OP zA<~m%!tA4tg{dpBn?YkAKh=@?`W>AGY#*l7x&n)1Xr{RnX`D)MLfepwq$n97mg%&c%sYC+=zN^C|ZXnf7#G=}+M57f~E!wrRQIeZ+yyWjAks$e% z4XT7EqMvjHK$o6uZ0~BmT^dzHiT>a&u)8VAHF5*|k%kX*5}eYHz#KsiCBl-s`N6%o zMQ8y%%Uv+!`}ZNy!y@Gl(Uf4E`Y*?XP=N^`gE8Hu@JQxaUg_eNEndsqkLz6-F*)qq zY5-&tMRQo3!)l~O;-C&Uqn^iDq-Dk_nAE#9auM@erK(-GLB@@mO=TuIG+@BlEeYpg zx_ejNNN_*DF@I`OYaPtfG7tuv2o8#66%Q+* zW_!bpW40HIb+7N6j-TxfzPi62n&MM6$n#4Cv;-F!+(Mx&4N4#N&RkVK&&2)%v8qmn zb9{~x**vK4P!5-4j8QJExkYr*&gUbN-8RdU2Ze-?mo7&x{I;9GL*8Iq=o6zoT6#Ba z166}N%w>V}FFSB(Gfv-6UpSf`PTiSH;3!O;$X!0X8!NXV=%Qm7XY=w7SAbyAq#MgZ z-!!n_>swuBbJdyS>m_6yP}q`wEh%oYezO1R1Qm#5hRPWMhM4RA?f*c^cdZijWwJ$% z*>%*;)O99)+33_^gdK>ybc^pXT(zoyG!*8((A%dVnnpq#dpYAg-hvx{pILjYwdZ~2 zkv{^i6FTvDPt5jC;h`+b(1TvU7JaO|{#$5!noU1MuSQ3>xVm%+o$ahU=cYK>S`r!krUCHNj4QET+(5K6s&Mtjn#=;A~ zifzJI!>Km0HkOMT|4;E7u7FU z;L_*QAjKAq@p(SVM4j7^ z0oU_w(CRRMTHe6k$6%@~5Ua=#{9qO0g(#eK>)pQuwS}3L;Z8R0w&gWJ+`YU$b&AV} z&mXMH;$9Cu(2x)Yh}pXWC}v*m#{kZnb8c;adq5KVQG66C6tXo}wOwS6Gm7Vqal^H= z?6Co&OY7%6Q?lqO#6++S{XId)dbkF~k^7lonFGzZ#X7jdUgul@6KC!OZBXp;6%!Z7 znJ&THp|)Za7Zw?;&#n|D2C|wzwiM#4jO^cPbv_;dG5X>B>ldjwZHd><>5;#ukjaSq z;H2lz28xrDwTSQs7L%(FQHzW8&{h=#zVzR-8Z*ku!g8;9C_9UsMM8_R`xm1$+vdwK zR7p{}_EpmNi@JRiR+SZLsmO%xWJQ~>zL~ffzh59yxxH82xOE?(LoMsfot4)j+o^Gn zjA-h;16A#Ezj4v0Y56|`f||2=Zs{SA=q|bVGz_T%cUESTOslYUifGuhMBWVayWVAq zzVf@th;a9Hfd9NjhRV#nt|n;1Fugnr@~`dk~NIL_dMvqjcQZ5o{8;twZ_5Zok4m zk-sgZ{8SZstx&Alt|n?iBzb#(&1R}<_9(JZYlYD^`LeI$W2;_3=>!SsqD0^_fB?fV!ByocE#t(hZCR-Z zB7pAJ1yRzZ&P%V^v#=%^MK>}tq^0If=zzO*UmZ?FUJY1Yh@tl535j@3={sb%t#Yfc zJh(uiZkGpV4*iU`b4uWS`u!$_y?U<~{&l-!`?-Z5`&)!_?9-(2sUlPY@T0$<_<621 zJW2^78LPKj)b^P!o;}KTlH)4SJ`?icmroBpK9SzhA&#h0Vrut9$=_A*{`hdHJkn5D zBLlTn9BLSFfCGsDqdB1Zyf`r2^A1nh{w*0t`;FxMZ9_0^M2Zr|DByQ5&YY^9EcLE^ znecyGRbgd1fX{V_m%cd{PT|*VR6Q7PY7@7_m(o#3U!IGWfHV2gTHfXZspODu4hy1M z_Qx|!|Gd$MPoB1@cy+~FSgv-3S7zQ5P(AIBXEB_*HQbgQGb#CXOrWnUV?DElU^O4I z^{bdut?E$MQor3I*V{HV=U9l(PHslb&sI1D*~1gs15qtN!3b~~Gq~|Db9G#m5HoA> zd-ZxT=b}JE#ZDFAU*bUqRy@m3V(Fn>Isym~^7Pkb&sze$=d4V z&`_vxl$l)A`)dDlfDi`x~m$%u6Gqm z39{jDbD{;1Z7e}%EUic_78sL8r38yyi(JNv4 zVzom-Fp`k1>~f>`UuWEO3c)d8k$pZnn{Z+4>$S`bea@Z&Dh>*KC7z!CO_hQ(khS&w z7P|igu(mmZV%d2E8s9AOvlbta242S5!E@m-++uj~ZY87#uheO?Hc(e7EUgLTHD8{G zK*%ajJ|~U{@q+%VE05=_?kz-D8YQ8;s6D+ZzAnQz$wN1_mbL-A_;>2Ca~EH+Rlu!# zgXq44S5^Z0HCi5`JV=YV$LW7HtwcW~VI8ob<8dkmU<7a)TQeNLPepM-`P5!ZyudQkTZVTZ#Y><2at(r}@EzO=NI zAstkAVA`X}OHrAP1=m3$4CPwumhxC{cFu0&;z|CUIV?OdHZy_ zhg8u$AA9i7d@;M1LF~1se1TM|A~G--oLj!}+z7B6$rlh8iuh@{w5bIHAU&E!t>66& ze+I7)A{WR^ev6)v4A7Vc{Fd{mO6{*t_Y#f7hOC&2L_hbPMQfc9c9cNeIZkx6UvV7XI{ZO5+xGTtNHV80`j#!uy- z?n5Qm)|W|4*%4WRTt&%69Os|uLOTPrDD8NxvNtYxq?-*ILOHJJV^yzM-yzrMa(-~o zA_9b>I_=>g>8wY&3lFmRI4_#^e2PE?j=XT6K&x#f8Go65;(c|iTV%iUGOQs!(BSdo zyKW9zE{iqu3JZHlh=5arhEC^5`u-pV9+ymOe*p9*3ZalOv;Cmt$W-c)M-&gccjG)l z@lfSwUfml@ol|LSzbv`8e03CkpWW|9%m9AK?s*+|d>FvOoI~ z2gYmOyuGR*xmx<8Aldm+qy3t*RxSR%Zk|3HvWfTa$r4H8KsoGBCT47kDbtHGntJx^ zIT_GKD08mZfSaw8 zNNl9&F=KF_;cdVrzIfnehs!z2ef4Mw>Y{c?rTPZG{kH>H1sVmUQxIA&mu0n^}YbTU1L4{yw4hbpVo^z8aoAi z<;>-3Kdf3Uzjx+WD}h}}GdHRn3P#s%1UsM{CGVj>bfAlMPguE{fC-9izW-Cdo>8n1 zb)3Wj?bL1l2~^HZ1Mz;3%OkKcZLUhHyBh;!%_2i_%7XY|C<9@cl7-5fd$%rA`#J^p zy`le6K`7&6?|2WOH&<If~OllnI7vOt05BqEU1E zg6pC%DE}2F&+Sj5MF4>>R%zqyNTqDtaPOJV5arki&Lt5ek7em+E@+a4$T%|H=vvy5 zHD6;XBu#FL{k@EcG|Vx-L5FB)N4b3c-y#5KTS+{)dpu}lw< z26fMiH%qChMz*>gio@_Hemz!NlRxcW$Oh>#*Y7*UAZ2oTG~+UgW<3UI)3_zi>nPN* zB;CyB%qR2g$&ZJEwvQvG8_Kk;-}cIL00f%x=Kj8~_ROtwclPe;?<`JIz>^I#vtgmK zjrDuBG?zqx(`Ii66#5+5*JW0mII9j)M3G>Dr<_DLSM*pEqUTsF)OnfMMPHb@uzk&$ zE}0hC5~`M#nacfOZ6>|(sfHFXt~?a2+5$}})Px!u$L>#W;bc(I3}mfETZd5@VS+N| zg`{euOcmVuq=t=EO);?h_6TI&J;PdMN_`@dJhU5b*NsL5$8{EcuCMHH^um|v3tDY# zuG`(os&9E7^7;h_)LZyN%}Q{eCj9iB1G{vRh%?cNph{o1F-uX68AWSL1rlvRul`zl zmPjA-s+GQBccupc!WB?CgO^y-Wh>7b=kb?|x&h6Q4uFM)%)W6~d=T$Ju=-PS?N%FF z%Mq?|NM1V99Vm-py@MXU1=x$+KQ7m>&K#m(Om{LDS+CBu%PK7#h)0@?b4JK7>xxy@ zlrg{e`wJZS2uTD!a75Ws`xo`*8<28dSGz;f&{74&_=f!iqRRcTa`DYvTm7}ma&I>sJ%`1%N=AmS4f%0& z6^68u{_FHVJAu{;K8j??Szs8o*;sMBoe%xjDG_amT}?| zeJv;RAc-{rUOzNj90=M8E^C`T^M!g4sItfJp&u#Q_aMw{cNU{>%}CS~F93VJ89SYV z$-1_PQ597UMmlz4eZL}iWGMY?rQMMALWUOOZ?AdT`k?>HdXgV{Pj`ZW|K+13*Bc7K zM5aI0C`puFSj$Jo+RU_vfB23jDoy1SqP9GEE&W1=0Y_EFAZfXO8Ta!jJ#9@2I4hRe z9Q#U*q+OSx7dL)$G4%?hRG_O)M$dUi7JUlYl9?;0W6%-F&QvNhezT_Q)c|7%IU2LS zOqa}ain)Q|;jxEtG4ZuFy~8vo1^{GF1ZzS`E1?n4$uMWz%af_};O&V(HZ8E#_GQc8 z%8G4>UGThw8a105EeH_Q(GHGZd>p}UgRO>+xNmRJe8F>i+Z-?9Zc=fL@ZC~psvh2z z1eDc$HMT`zOhg8{+~46gwDa*p zHlb1!Ev*mzM(L7(ppveZkw(Q1&5bts(2o#=wcR_o0S6t_P1x4lpjJQ#A#dlO6`uJ4 zU})7KTYHyPI&1Ns!kF0zJPk8Y*rC8+sX}2JrwdS^rWO24thJH9oc$Rlf$IOzn-JVJzb=gq*?T& zygu^C@$)pQ?}2KfX2JVC>|g?iL5=b3OEv>M6w2)m--m5i4S{tzd#&3yDmFFx)ByIP zdH?3m>A29Uat=C!XoL%~-0W*2u$g42K(Ey9KHqtogPM*f_X;bTjGr16X!fu+%KAHt z!I+r9uK5X@%`vN!GgYvZku!d19CI_KqymriSu+u0`_=pnqL|~cKAso+TyA-o0WHP` zSL(}K3!=7eJ&*b}+GyUeXamIJiqnTgeT7hN zY_uD$A*1*rg9XFxFQ$Ihcj zs`&JYM|zo*d?dn|Sq|-A0o?M9eV9_Q9{!!*Ak_==L@hZ%bxXq|4pUI4zX^MOX-m^H3_jwil{oD- z+=*TeBBv2xfDl_?HeO`1-830rvo~*e;&ZxfVi6*fr%us8O{baF4FrFf<>qdiU@kl& zzG;xSJQyb^DroRH;)r7!Iv?9(S}Q!%tucf1Xu(7WC5M-WTyU@65yN^6)`kA&jtS2WmeoV~YB*ov zvdSr4zUOPYOLDTvdco0Q63qp4`P5Il>BbnmeZ5@z3oB53U=+)I6SU*u3YFuk&`>8Cx^PTN<T@aSScq~9r{!Bi9vtly~m|RddBTK!yFSnPBWkH1!ptfDuPFXxZ*K|so2Cd<@g0-kZwZx~#AU|Q*M;0XVmul^m^(a?w56EJal6TO zDfq4<>}l4f#uxb-mJQvIFDpy*ytRs@!A#_12j!gZq({SFU>Ye*Fc!g7?uU7LO{_^|k=z*Ro+)iK3V(@b(KM_%)a>6OS{$5B~FxiQXm zelLQ_&9H|RHaphDs@v}U+oHSMtc@GE(P;L8Kl!dm20ee2N zU9)RqdaA;N#ux`jNizS&#EbjL6cwPs#PA7Smju>n?{QRR-&cC72Q=pP){|M)-dy6$ zD$A+$7F&LOMf%sK%v#EWYO$;+vivA)?U;SBGKL$v!384lv`IEh|46)XBy)}5HINfQc^5SgD-;KMuElJfk|*av6bZq zdJqUW45t&vQu-_opWQ}RbnVsJFl)WrINe?`6fuPZS)#34$XIpAXQp7*qLX{*;So3e z3Ok0L7>NqQE24*rr7BxTNfO81feMs_xU4qH5(opDGQLpmuxR)Ddqdi5$d0UN$ zaJ*BeId5|}vC%2tf4u3abF9f*HeTwkjNx!%qgyQQ{J}~G6<0XARrxh5C53Fbrp>h) zw(l;PravS~ZmR-igUYnfLDQPO_xX#+!%#U4(9b+SzmWd$sw|K_Jsy%=6`nLgT0Iap zjvLb;9(V_H02-R2$=0ppCYVJ)R&xPwSYK~v%qqk?k~eFoV>}T#T7eaH8&mL`aCrn6 z_fDhr>z%SayTauK36LHl>rXH;CGZq|jYEOKl1oe)#hO-WEvYIeYv`D_KrV)PNlS;r z!fw~hO!4RHyqXF>wx7AQLN7eXB~V{}~tldG@xi_q{1p7=n22$lkv#uog!ggjVzM zZfP05PE9HYLehX+hO~^#R1|Z`R5f^B&t2SB<_f~pdaoK{7$NRW`+9C&_i|yr;ekGX<+O!v4^gaY z`;qhu0_i$arU>FJwq1^A2Of99O9ucoC1Tkp(@5+SAUcKstTY;5J`-dP9tetTzN|O* zK~pl#>T!$dOwl>37s=_RwEwbiBlOdoz$p#S_1tQ+@pj1#yj=8JyI8}c^Z|!~ArVPu zKx1meUS);Enq5;BpX_~H#*=*PlesACBy$==ZB5P9)#*C5GAJt0*MbV^w!S^2PYD2Z+#CYiHiW{RcEhAdj|3tuNrD00p?{u#wHk z^%KWJdSgG4_q)IP2{;~X^~}b~0)#~Igm=zJiu#72`|N`xkF^=KJrPaJn^zJ?8X_Ss z>My2DkJOXKDq~aoqGP0%F@~QC7sd<`7C$8=*hP zA%NOEw}{Z9wOi*7{t&_x@g?_fzh%>8Z-egAv&eVN9M!kt*~in4nvcvPznm*&nwy(@ zQqEi>z5&5scY+*MDAZ!X%5WcU7eN^%8443Xpi-uor`N*Bh}i&dVhs%gX+8=PO89n| z2!r&#UPTem;rg;(;^eSFmG*7|b-j$`AS}wuu7nz(aK2)`BMpG}|S z(N2~Db9MVg2?2&9oY9qk`F^|?nNesjG+j+f#RhsW4)E>wdL<1Dg$D5y!Ovy7uTzt+GY1qjGdRSkKf9 z0Yw->QRe22`H6vTbF!<6*XBsl2vL)bUz}{m_(JOL(x(!YvaxY*S+%gLDbuE-vdYjR ztZLSSrA$e(-cFXALRz%~KwGkK`7l&!=#CagO#4V(7q&u_YuW`C5UG7pQ?H-KU6poK zM-f7U8&i&Lt_@-6n~f(@Vl=GTbo9nooa>yI#SZrU^<-KG^=fzDkEDpwVwdbh3C3^D zpV%RRiM{nhF}c$@=D1QugkX7}Qs%w*h$&}yQD6A-Cu)^t%+(3Y?i`lK(J>M)Cm8(E zYLB_)jxtwji7D-=itOjaOv41BZnooVF5?~!@~7a|wR6ee2qnskC|~2WC8LWx4GUG{ z*AXU^YIiZn?iS^-t&PxiRR3yw$uT#V4!~e#^xpKN0dv*3{dNlMcCg8u8j>WQLl8vT zH$Y4vx^*}|{FCd`O)I3l_oKDx@$1V?>Jn2fHZx29T{D@uLNx$TCfObD-MQx+$?wNl z!Y%9%v_-Q5_tJw)>nJ;RxN$KURWbjYZc&YAb%-`xGK^F1O zq|a=dO=aPj5dwv~Aayfq%4C?GWJ6UO@U&JV%&6~4d!e4YbRHnN02L9}cI>b>CwE)J z3Swa$=os!;04rTGNB+T0ud=Q^OIK{hDcxHD%(d9r-nz{la&5hm{GUd5Hfnxou!cHN z%!zU0UmYN#15#@Pu7FlB?-f(=fzdhD`|Fq4_OJmFC08y;>7BmnM&oY7tJ^*efeT?# zq797>yyDDqQm+p2g`|m|!XZGf)OKp`VM09vY~F+XgO@T$ar+_?$F2iv&~CNO-d1(r z>?e=FqXOVq*;qaWlDl%5zRos;ZY##YZZaB(D0 zBi-lfPcM_^0|6vdD&I^i2QRTFeixJ|xI-ZrGCwPKtvg5=sWri}+lkHBr6d~KyqEkr z{gFxM38mp35+$5oGJ|*Y-WeNBt?KE~t-CMmNr5uz86Azc8>msN~d1JPF6tE4LeLqj;%9HQGP2W#%7~xR~RfG{xT11px8Zck{+;H}? z^qpP2`PLfU(s!5)WaJtDTATufGdh*CwsX+_B__02QOMEphRv8hi?>Vk&v7`D?k-2l z;Z9Fz!{&AMZ5b(J4H;8Rb7rgroZPjz?eVw5)pmgV6Rcqyv0d?D4G5*KZm;Cf+E3Lp zc(&dKP8$Hd^>zeFL}GYcHBql`P`e`;68NJ1TaNFk;Ek&!C`vv??qgvP=3Q;~$_Fa_ z;7C0-)K16S!ytr5pA_cm#{iA$Ez?a7D0mw8OzygTz+Lqj1YI)4yt8wMcLa88yUW0r zZ(`kp4V!pet(|07+2%doBX?n2(gWi6QjBW9(l0=_-P7$NX9)6XM`f;EA?Egtz>?79j_?1v%%->1 zaAz#LZ=?I|WfMj3YUE0jnB_t&OY)h1^{RO2u@;eMP_zA{?^YJewrX7E5`UbIds;Y* zc1q8Vg<~NyJ+D6LI7(CHYwozkczxW(l(?+IjB48>$2jdh14eA%REydr$N;VV4>-zv z61U?-JAIEv+=)glHx~2$4A^|m8}&^8*{ydpW?#Q9F8h^9-`^wFG>;yy@5$1&mGc3+ z)2(A1M)Np0@D1!*)q6Mu2ueZOcnA2Rhy8?Fmh_fNa!zMqXe*l}2eGJ-D?(ga-$y?@(o}ZTTP#hVCKVsjgTS zrqwO=ktzcJ#YRGZETo+3BjDymZ37tzYgm%i8QcAvO1RkjwjWaE7o})@yru3Mz2W>_ z+3l;j)k-F3gMq<~&W0kCe$kqII#l8ti|)^J1sT5tzKmXt5ra?&?gT*Ks9!g88kdA%DMl8eF( z#J3+ix=2omXnj8p;6Ay7Db1v>wtU|o+%!*zN`kb?y+BYHWtEXox!NfH;|x=qI4-l* zCa-G3MB4OWay_WuJVnxK`W-|R;}3_1coB{@Ji&M(*;zl0jd^GDIP!xaHD^l8q-djinIvL3s{kR=h z7-A?#TW~eTCt)PGI@}ThCwAm@4pWNgXkcyBbTXK;S| zO5{J{C7)4tj<^l|04a5wcsi<1MGTGuA-5h4nyv6R?0s%&Ru&0VKhYfW5TFvRaDUig z6EYYmn?#)GYd%zib!%2sGYR(FRp<{Ww3pzmr{y6V7jB^>6D`=)@V9oprScbx+sa-W z`owp9u%?>wbD)@rIF1!D@Bp=lFkfFliu*Qhj*5iT2aNQBUa6ZXMw}4gVz}GeG+ASy zW3azG7y7CHcH3V2PX0btfRzcFW^C;q7cke9+hjcP{zqNMGHc#rTdq|?y#z2x5hB!d zGcyi zh0&!_sI*cf+@X=V; zDB*Y&O!;Uv!Z?CX(zn!}%?wORKo%w z7Mq3|$bbZk$5jbaaQMykv&JTHN;iy2}N)Pqm zRX0UpnT@Qi)~xF%uKRW5mfDXLY zrG!_y;{^4!e}|gBTaZuTXhza`S_O*=;R9rXW~1Uj5P;?G5L=ybGQa;xMGg+Bu|-+| zeP-=rQ<>g037urs$Xe+Gn5sGaivv0U3)1$PV!lVP_Li@I#Bh#g1$Bt9LUqFc3K+!;fim$50v?TyUE?Sfl=IGG#vbav}a5@%dXi4ua8x~x@MpGA**y^0}u7>Plp z@xa3QViT(yaa7eC%5Cxw%5brS&3)G@P_x1$Cr72{J^`_!(dJle-7u(R_zvi>XMB9v zG!H!owh0=?A@LFmSOH@V{`mQu^t(1AEyHNXTMqB`l%O&oPXI3gc@AFAp5QHEn^HB| zkK@sYq!Z!VNWCZ_LzO z|Ed;M?l=9(BN%HBB9l1x^bh=Awi8XgsaFw`iTOU{C~~0GG}&4ofXI`*{&Q}BY0;6 zv?BPGuJ=PFx!UWbpdbjXq6(Bj3?zLnZGMLpHtDc4q=iNDN~yMM({_4I8%)sUJKPkD zGH<u2qfH?f5X{rR=#r_wHZJVDj7Qfd zKj1T>ZVABneVUi!Ywd{f=*?;ejr>Do zZea1T@W)-h*3sld?PbKG%QC36fVRU$zVB4{RkqJAOlNeZ24A6+x$SVpk;LJ41eWo!)?nvGTba{yq=Uu|EJISoLbK6%bAYkxQ&F>t`0Mh&la5loUEd5!;IQ8GI+x*dY zIgGUo7%T@vbs9L^7UwF6U#|pOJPKK5-+wU34z)`r`;aM$&{=ubcqJWZqHqF@<8w$J zV$n=2hQ9~fAt)wHQh>_dT69DNN^#g#hR1lRuPnS1sfhcm$jSVp;smg?JhlGjF{%nK zU3qKQ#^cng zFQHj9*6*m@Ap(^ApR|vg{zmF~2Bq=I#Yy7HSeC@j&R#Iu;$@u+%l@c(36YrlWa|D= zw<;wFLs$`yFb(W;TMz*q*g(a{)}7i2d=t@4XRr?)~<=XawRXV zA>L3}@wL}qIlxYypLk{AyM7|%tBA$DLw!^^2UM#G{R=j9#ZJUjemm9u`pyT9YMWJD zMEb~aHEsVk??d>~SnFkwP8+qeVqBF_s5k3yD{8C(iWiia2#K@jVB*SB7qPozh-n%` z%!sAjc0P3G7}OH!cn+V5+RQ z9U}?lx3TZUXyDj%A)ZV@1~0W?h6F~!;zDMlh%3xl3b!ftf@#-M<&!Q6rE+(CM(R6d9WUcuR(c6z9l^Z@T@i2E(RBz3s$nEop; zJ3Uwq#H1m?m()l4%f@tbOcA>uiArm01J1J6XhiB>V~T1xE6Oe%5`vtB3EZ17&9fUj zoZR6A=V*7b)SdTvDIh~z9J-h@gSPPFfcYN2nOyI9R@6loH65ZV1T;6_Kdk5?ez_=) z`9`__3lV33<0>}}O{br|tVwpUp`vhE^J7tuoqVSIcF)y`!w8sj!31`2w{$RJ=*aZz z9SMxGpGe0BT$>^aNhMED{RR1R_Gw8->WmG1-uf&tnJ>g2JFdA=OdHpNtY&X~)qy9u%ugvL>AXiXJFf(gfbhq3E?O{)@d*yz*A zN#?=Ng@vOfKBKHRTL zx_U8&h?f%8L=-NCuPKCCH9@65+jEMlK$DJJ27Ud0MIeBreE1{OxR#s!GsBNz!<%j; z^<+1fo*oszE_nW&(G~MuHDjy!j#B0b*-_y5xPRkP(q)ktSL$q7Q|FbN{Jw{1`Xpl! zysT!7iqcrATY*+OqxU0P?6O$$0C|T~Iyc%$y8y&&Xh4M2samuWC)CBmFCo@l*|s$j za%n9;3kT9q9u;FFtquwp>mk)5Hy&ZaSdPl&34NtZB1{XVBbGJgw#p z-zQ9{^W-o>>cVEi8ErzU@~u^SU|RhQ(TF8iP&k%-Z@Hpka>kMp4_61EU4E@`5^oup znaVXzz=eEDjzX%~y0OjCeA_)zRDi6nY20?&>FAQmTR+D;@&mvy=`u-YyeIXl1hwy~ zJ1$6t{CWIlf++^j%V@#BYPOn9@urgt<+^(vt$Up}4q2R6UmaH_Zf@*Q61MbNQrD9F zs)ZW<%8k@mg#xT4lgF2fjTeI#BDNON#41-wH}}0G1D58#4`7jrIzb8C3Jyuup_R3+ zQ`_D5{o+)eZIrBo%iCd^+};fxv!A+w*1!sw4oIXy)d=>LrA}IHIBvdY6z@>icGJv(o5M)>bAuU!=HTb^W2)D%@eNooYI*l0+3g&e(Fb+3m zmJxLrt040Kd7mix=V?)Eks)~jQ=thXDUeiwFB^?F?ICsj$(!vDj;t7gx=;$KPjkb( zm`5q#xqrO}NMg8e=u97Kq;=SZN)9%^dCO(I0nd=Tw06CR1KMyCg}ewskek3|+tH<8 z7u%>qOs#v3krY`4o6Y6l(x%A=Iqg8`qfg77@D=p>r_SosG8v^>Kdiz!rN2X-FP5aI z`1vnOqz=_4PM7>>JU4!0Kx7i|FlZ={M-T{0h}mMj`Q6#i|@`zaAaUdT_lHP1jLSCGVGVtaWH>;8Y^L927AQl5aGgx%rCr zUt5i%N9gzGys#tE^rWh1t~6=E;|ZIDpTkg-llo>+sCxfSBkVhS&)`Imf!yxaMJA~d z<_-0=4IL*rdf=w?zr)ggADXtj-286%!3Uk?FqAt%ffy^aHb+SvTPS9Mk!#bmN9KpL zFuBmE@A-WXkU~jk7+3~;u3K98KEEfOk?G}_duWvErnj!;&fa6zh31w@3p=7D<=~6Z zhfAxj*?m}Tjb#~u!wxN&1ter(BHCyuystBeo-Tr?t%4ER!E= zBG1^5j;WOIYlt$Dw?_?nLYPQQJB-H#IvnpwvhMmX6!)DJD!#}8ny>1{#@~dcVociT?0Y1=-=i%rT{TmMQ z$pMFhcSS|5;DwWG;yDl)9h4-heb0Tkcfvi}k0k$?=t^#(+%?n)J$IV2rKpOTd`Dr( z7`vtRk6~#>Tcvb(KNsoC?wPf@x^C8ncS~bEoRHFI87M=-<*emH8F!}7=rx2vfRuSs zpdyZ5`tQ?2DIukrznX?g@~JteXDz{0DVSm(`lV?oRo}sGzUpi!?l&;$X=xw%+4mc- zT{G6yP)`~}7~1NqHFgv>*BT~#$&tFvM-D;92f5!*`dB%3TDG4Snb|%ItFD{QarI!I zJKfkALrkl3nQJeLcRz)5WuM)g*Z3PLuSY7%Ke#N}F4u1?Re!++!VYwAY&A)YUIum%=72W z&Fn-MvpHBCmQ)V(R~+Ry<@xGV%sty85h(w40>U&p{AL675(S=aF2An#$b_tCI*kKe z)0cVER#V^7AJSwOcWG4C83s^zee_S;CV4AcUJkJ;TrYUOmRFNtseAUwMi-IR`nZE? zT6C@rNl7)`hG8u;Rm$-fUK0yIPgGP2IeSzYHPFOEJ@Ofri@8H~{D0A~JackdKl~zU zu_aO5bP0Eu{dbuSm|}L=G8{D~kIZKaectic>FAGp8%HIn@=YEy!0x^oUPrfnyj40} z28-~BiXlg=;dpHSPM6!IPT; zFkk@pey$2{4KJsCVZJUAAOf#wZ7Ez1RKbX#E(+=3}(ndR{mDq>Hq!SZmjOfTATOKBuuvuaApG({WAk)=k zAN6!X6~XbLI*8#{$!LG`_1gFfmV~YJ@Ak{)869#bpaWt~flJ zS7=C?P4o?gdtJn_ySg?HjN5f#M6K#?C`bB^VmgmvK;ToQqkvK>UGjjNkS!ctB46gYuEM5;tR=dc!_^S(TkL;4X1`z0Z)6Zqo%HN2IAhd{0S|JZeK;Ff|*kMDX8seM{PuwA;H z%J@1P-cI~ES(nE@H*P(3HWAPGG0^>kK#_jbBgScuRolCYH;Z}7s>A?m565Kr*IY9^ zF~PK#lPLLjt-4zohk@zh*LaW7<;{@5v!uFYUHfb5(t?n!hYgIE&h;cT&4U5?bIJT2 zJc%+sm2WzY{!f<&fRxf^&MwJ;YXDU|*oL-O?jsHWFxJwo2e@adzRGSw7m;N(iJm2B zLgPq^PQ~c{@Eky-u-ax^Q(`L&p42<15uD!9rq6QWFBD3rq&{R~Zq{kzTyF2*S%Q1; zpWlD~{GZ?)Ztwh`Rdzml=Nkcw8XW56KPv>Rr}M}T?g|gue{X{Ozkk2DQ1AJU2>j(g zVK(riKPD`0WPS$(&m)=tw|n63_3xkmBZu&NHT`?z-!VK~lO_2;%H%)S{_f&`KM>GB z&KVfEH4Xas>OSxJr|g~OzQ?71|MH(7K7^;H;698}jaXtFiRwR3!jZ`EaUV`rag5FpK3?*#zm}W z;4hE$vV!)1#!puIpZ8{g0V9j@dmsJ4W+Zr(m;MKn=Zu_Mi8=M^L@|EioA>XB$N#Ih zV3~k1;=He;sYz<1H7;FEzz!?lD1)0)QNbMUQN8_t{$T84;9GMSScfPMTJU3C${*7fvbg0bc;q&4zh@sWfCMcM!T-odNm<{C-9B^(xNB`>*F$9~U)|JS{DtaL%qcE%X~ z*GtQmi@jejFWlkfEqg@qU+d?efhnL8cMcrR*UMBvpD4x?#j~7(`Qlvj#~Td|#~m-h zMglj#JBFZDCm%a^_}7~}MomXMGT*8iiI4{;Ztk9q-^j*5t^Lvt{G=Iw7r z9k<(F;AYI2#sArsq<-)Q7r)ehF0*J9va};mZLM)0Yj7zN^1Wp(LqL<+MYWuhk@K2A z-zLM;eeao>CTU?+Uw4krlIF8Q{j?SI)3UnEH$uW;M!}%{hkvyHd`4#d{9c^qxRO2h zoo7j;@2URV4|QrbG9lC{!x(9{ShDm94)!hr%rnF+`4ZS6>>w5}L1oW1#73DLWT75h z{_mC+7sBYXM2hli0~8Yk3k~9rqDG`vsHHvq`PuHYZ|`WEkfkcY6x{_UZnY{n4Vl#yhlR>lSH zqJodaZ|}ghr>9br_Rw#=>BrxZS|Al*R6?%5A`#*;*8ILBEJ$@-<;Tk=$8Um*fe<8|j~SDPaXgsz~LFtKTb3!Deo# z)2cl_O3|+FSFC@HUUAtbFQhceAyYmROH&^McJ{s38KJkf-3esIo$~Fn-e^DSxOXOE zQ6#R^d;{Bi`nlHLR7{?NhFF*1srP1sZu_RGdWPd)%cj7pCuaPw8U4lLQ{6Gc=fmx{ zCZ0QFIwIazZ6@n@3Lyh%7YzuaS*4>~*J36hB%<+9s6bCAL!}X~0)Mq&E~>}o_Ybkl& zit;~Nk)D3;T`%0b)IX4v35NWMlo?4^vS}Q8Ztpp&3ORe#(lR^iy}DDGeWOmfbC$Nv zN3^5mti@2t(m)4V&sUmT#BG|)6f?|8k&~Mqnu!r)S!h=YbHyWAX^cWPcrB%$xbJ0~ z;t#i-ntiQw9|?|}7&$rGeU>3Yy|P%O{J{OXja~x@-UYA@wEy=yNO&JOlALv|M>MxT zHRcXF(?*vcMFOipwDL2$)oE)uSlF>#bKUQ~56QzX2MM&Xw`>Jf$tzyO zg$qv}qN;5=rF8_|*%Z9yE!<`gTFp1=P>!w-m8s~*pLL>>w!AgXvfS_s{evTCR4MlG zNuL5?jm75HwJZ)faw&4nthsvUd>i_PPU*Ek0kyvDw|Kj=7aoGeVD-NjLqI4B*!eV1 zcb9=(8(s6(VNS=FXI^4`Io`8_OP_09a<;V*mmC+-d0v*XG_U&O2{uTb#vNJXwac6D;1 zIEi3o+dtX8!k|2kh2T$ zsX1ao_LRysxJ7ICzZdOmNW}V<+j}bwF4d@NIg;)S%*)GEFpm$xG~&_}!xcH(FAIm! zCEU!NvI7o@YBlCb;qfv@ZAD2HrUO^m4D}uYdL7Qu5F5JcsS{%t%8>(?%Uq{!;tb!n zYUrSw|FPI*ih#Pr@d_1BeNN8M9{eh&P5I*N$Lz>aA<%sFY37}LuUFVv2kv#QLP=SDfNbj4TEMTks4~w^cvMZd@s}Rm zQln9_wBs5fC6Uw*0-!uRIUc8fn`y_a}0%J|4kE)|BZ9lB{7mvRWuH2f;glLnd#g^V>-h0gA%J$Tq@UqlQ#TnU6wR4qz88MIMlX-+wsJJC?9 z6PNGrh{AeXct|pu!QN=~2-bNOsi2OUSzBKJpz2SR1qieq3Qv4Sd3sp!5bJBx54F{{ zof2-LLe*rFQEj!vK;CG?`bQ;|$}y;!+ULVFD;l-+E^wE1rC4D}5l0GfzOF>&pPAD- zt0EKGPvwF_I_p2gqmvAHJVX9i9gIC61J2FQtZ({$xxdJ0FtQP_zNZw*?~B>2bLhr> z{l${GxfmFQ@d4(jt)5V<(TXA1?Hk7Sp=Wr3KdD<2c%Qs7_j6~@E;-O-%L#U z4#1De;ezU5o=ZsK!11wq;-UNa+9g2q^*cqTB&b*@i6O-}3B;;W^foqLgR;2MK|E-& z<(!0GD1(e>J}-8IW425k(C2iF#S z?t+UD!v?!C_M(1wy)jeN(53_9M?T;J1;GtwmN4)|P)(Qd+P$mH4-x{bI&u}Bt}hO- zdY5v(@wjAJXKf^7D^G?pM_@$tp;ZAh^{;in4vcYUs_;&V19;~||3;ABw`#^Rtii-X z3^qJtX}Vq2QIKmwI)n~CS1s@xv)Zn=qE5PwFZkTi9MFO-ZS4{+qD_HTg0f~^$Hu$h zZtjwdq`kX7)1=ooBy;-o6Oz-zh2}+@&n4h9@91e87W7qE?copKt+}~SYbUk)i9{uX zE#ewkhXje!j&hwL?tp45s=`O~}nvkwhOsSIL`u_{GanRj4>$}J{>n9ty zF>wwzxILZ8mwgcmA})#4mDmGzn$t6yNViV?unH8-WoY;dd%fD@#Cj5bcl+$kdPw47 zJ&VN9nAP*&gpQw%6J$sf6-mBdM|+2!b>Pb&prAKbIUi*wQ%$NfJiRJrR4f2$zqIme*0Z|c;BQ^fYzX*isEvs zRq`B0K15%DOT$Uy`0cor6T$a$$a^)y`0MbQQp(@w`-^$G5)iti!?Ahz=eP*ABRiKr zfME-gv;@ct|HNb0n#t>z26^$c0IAZX(z{jE(a9OV(dVkjjeWy*KWO}-$lVl7W@Ca) zp`k|FQf(NrDEPUqFu+U1+mAVkRUraAULYb2)Fy_^{_5t^YQ7%- zc56$em}EF6dW?@?Y%j|_(pkb2Q7w7a4V5_4V_gcz0cAK-eN4(u_kj~++o+0&Ur}(V zD|=THx`8Q%0qkyo5!B}$RQh|v2Coig3*;dtRB$Ksa#UUp#N|+W>+l3@VP>Ghm`N`& z!)lCu_OcW{A0Jjd6NOpFQ{pTg5G%51CN5KOd=a{r;*mSQ9o@gZCpntSbr?}*R*1*l z{W3`(0snT3q`&Sk>;THus`y;W^H#KxpfGs<8aB^{Gz_Cx}0_p~{7O_>&_zVNK3-^E=yg${7Dn*W*+{?ZQ`7-kwF+!3- zE7n@k@ryOpk3F8^;q9mYHvoDO4ENg?^tlWRC`GxDb5^1Sbk=RBFimGZ6_`@5o}E^^ zo7yXLV~v|xvPurbo&v_qPbIFB0|lieWm^keOF8dcz2q@~6YDc|cXQ^p=@~EuQ8q ziZz4cPjXfb=#MzYXLf#=1WcV*l_<-9hiL{hZSW+VzPF~df!*V?OG-an?M7ptzWgh#>B=J2)z(OY6opgrop zQyswca8{?Y?S6StU=TiC@N{S}wd_5W?hpxEip)H=?tP8Ze4|xNxPoW`+#Y8NeSjOI zIi3LXx2n3+)l)0G%Dg_B4Lwl9@|8SenQS^e$FGDk(X6kjv}rNQ^-Rx9rF&4s&;To@ zB{r>f=mCa&IORsp;cyX`6k|_s%x(^&c5X|$C)y5`3E;hPqr$I9hL{s~P5=hkp{D-p z`AvRUFenODScvHaA7u9J3{gS_C%F^UtM`*;w(AS;h=@GKiX{2Th>RkSy5%?gj~Z0` zj-J=|(G3f+YhfY)=H-Iae=(mKQSJ{A|HNDeF}Z(X-^R{F`XbfsDYO~1$*uV=GvZLm z?;SIb>OAn+IeKa1c5Cwi=3?gcTF+5}oyYl*QfomEi=6ZEoAe4MsIK~i{*)hPTX+R` zr}eqUP-?pD$!7JJhHB;MX{H#odB5<^-?(+RzvEm&KPg2@4rqk@(xWMbCHhs}@N{K- z{K@>wD-IISQ)43NAETW*8hh?7W~XgNo`<{m8%p;c>^=TjDln_8(W+wbdF%aM7Pxgx z@)4DK8(aToG_~M_GIosT#GSce-Jwq5_rnu&IpNmLYSR1igGH@oQEW`|5FVXpZq!|( zjt3g=d93~4{F-?DF#O>)K06!of`sI3dkr?Xb$kmJUSd|9#C5HSZX*L6O|;H1sb?_GzKta zb_86AVa(J52^><2hWl-;ZqH@1BxiU~VDw7|urCExZQ;PWe6)l7Dp|71$A-RID|A<0 zo$0Uw(T6_2WH44f3z$HINL+6tIC0<^47x-!w2T0d}9zf=C{{7URL}L3jvYjjWoHO z_jfxhGYMmYP9Bs64U2Nt$d0@^)Zgdy+i=JJjq2+C73c6hAq97ReD$M{K%PQN4rPZq zMen!|$W%1q=KNNp;plDooPW?9nmSKZPH1p%WIwTg^rg3m?8fzsgRo?88a{FlFZ9E2 z|F4f6u&uA=0_#lHO-p{er2O%ugq>kWBfD?~&X4|+w|)2k^FeHF)D=$YMOvu<_$5Ie z$W(|T zR8D`^;6@&kYm#t?SSn9^i@Jt+j==k$CPUL7jjqM#eQ3_Q5XA5>6L-aeQuhM^R?sH9 z{sv?r6chIUp?vHt0x~KjK=I6LJ=gHycs~{8sI#B82ZNJB!mZZpN$nbqC4nR)asz^{ z#O)g;x&4f61=vQJa-KlZh`YbrZdaQD1qfA|bOoR{XO{nYmfzJBEpi86b*!MXLqi;` z`XQh3j9USJTJ0{Lfw^?~V|f~SqI%SoNQAXTt8!7Mp&8FDOG`GOF>!qH_?&uhQBUxe ztv&Hh5Ec%aEYn1sr1!~>PC*=mcbbdOPWj8@@5ErK2csngzI(iGm3ikH>54nlGu$ox zhWrAv!#mVt;mCyA_=BU0Twj;n9ctr%gQOc#E8@kh#t=lr%;#SPcgMchUFI7GEnx>4 zb00lXyyKz|)QOsyl19p0Hf+^5-1rTYLK2Fb zyJOb#s(RKOqSf|{i~7}32h2+fp6pAK%lb{w4#5B-FnEdK%AO%9fFc}`>M;Z_F2K%&Dg&=0Ld7nLC>C#&aTiZv zGus7YoeEBu-KB27NR0}sjVV=U!1BkN&(#i6#Pbfl0xPbEDBR9w7!cb|O1Yjl9|9fk zOOyStyZwA-8zV_r^;LHp4hp5@#xQ+q%T_aGFd9)~aqT-VoT!^5i0tj#1likTd9O$?@UWw9WcZ?PAfd8%LZPy^d}s}SR9>7X zmh}eB$y1c71o>rhaUseHX|o|(`xJEmqfcP8*aWSld5V;7O4RiX!V=tyCzuZV!Fj+f3jxkzrh7%^Z2h@gORS{`>*?%c=;oNQ z$)?J!k-w$;8$U)ddJE>RM146y>Z)rg^NxrLE=md3?(1Rbb&u(0N$5-!9D`8JHz0Cn zk-7baBAMRC3FZ3>;2$K3(%Z!|q=>P*Bq`$y`KRDL{e*2pW1pxczj;NTt96d?DH?EQ z#ntZtfmx|99#n2!AD zaR#-^^msHF#SS=Op4*uYP)e>er9EnAB?ML_T;v4y#26MH6Y+-$i_-b8Ql%Sj#a~3- zpWd*?^cbpRqwp{3{3+;;X2?!^XNGLHO741prZ&>#8w+U1U-TOg2BZ;fQhVPoU4m2O z);h50?wYqX4mjwJ4tooa#RpA=`C~;W*b6(|tbAzL3JzvBPOAbpMpeGsUsGBFB!QELRbs73)wDB`j=1pRwj*qKkB#mWL`W8w@Y}~an&8@7f#tcc{tNHrS=kxy8H8{k#Wui| zZ(@14;j{m+(VWNj6O6v{AG)G=%>X>weP7{5*T_43$!pcQo&>cjg{{h=+u)S97VP>D zb9FW+*b!40LLvWQpER z2b^g@n|)CpC7As$(sL0pi>lOMLSFugoY7I-h$3z&(D7B)O^dQ!yfMfH*vQ8_WWJnp zZlkNY6HDC5RqAd(CneY=bhY03=ybI*y3m=%Kf2FvTi54=(Kw$!V9T=Q2*5Fs20Y6p zOid2h!)nzleobcWtw!La>5u?A$b81(ZSvE9W;YZhEhT=L(_d) z_9T)ZSZa4{hrp`8bocSVd&Q-@*1sCmI!bFmnZo07LPC7f1h2ZFo&d!>5o%)ST3Glt zm?SMGX~KO>dtxRX&!T)$vb;4qeMShv`jkcJC885ocpIsU$MXlWNtdZFyEY4>Gb)Qv z7}7TDj^Ero;mR2VqNPC{4b0@l&}lid4w8u9=|9UDxQvc{M8m>LcOF+Tv@}{1jTpCP zc~FaWo-B{jX7E_;KWu5WU;z&-%f8PG3xdT3O}{3Fs_T8UsF!xSM8UT(oe$@=qhmJo ztFfJj@lEra4wwm#?@N_$=dD$R!B$-iJQsu2B#HD=eP0iPm$NaELnd43*DAg+Odf=v2&5dzhR`?SE}tF*ByPsmRx+v7mqh* zc9JTU^U?lR+~B)HzN=|N_N(LNw$q*a;T-(?K8eHoW)-LV4$S|!az|bMk#1QVCQ2Nj zbnmCYq37*9e)`<|e&|qd=LCIa<>@n%Jc})!%TyYlFARpqkFNz`&=?b& z!S^Sgck01g7$)I;LL6G|&YL;vYTk|9eXLAkCmAH>{g>yYb`VaG?s50mjQnhXuy+;# zmpjXcD$0te$*vvM6v6$;$CWEHxvi><|4+R7aAitWctwVWD!(n>shBSjn6(fpw&hR|V7H;#fuvzs}2sk72ff(OMC1Yl+WS%E6X!54wR-N*YxZV8Tiax8WXb<){oQr#f z_0@}_={|gG?ENr{Dza4dR!%gTo()xCZGqF1+ zqEs6wSZ6+;q~4H#9BK~G`Rsac5g8CiGMXvtFk&iH7KC1L5(bvx8d>h5to@{(AU>nmbmxx z;REmOI*sGe_=WUw()c7*KpJQKHgsEdYAeV0fz=a+_^Pl%WQ6<)M_%y>g|(?JfLNm* zv3Cp_VzH;|FY_TkEY1mNH~P5T0sQE6EAcdJtW#wzVtwbhQYnA9Lnuzx9~>VKy?Jwg z0}H^i3HK|<6Mp%I9pFv3Xdy@wkI3 zM=ritb!^`ve?rgUty+$^5cIM?do8?EwNRfXRW2*B^ZGJ5X?(vj5rKNTTFa3+A805^LvE~`rD!ah)i^z2wdnx7s21~M_qditO|^F0QXJlCdCsy!6fJwzyH|f|eF>^5`z>+zmpXN^AqJ#Sz;_7S>s#b; z-c<1^GsC?#TY7pG+ZZgXtVa~}+ahcb&Dfj2b>Tw{6PzQ@U1rO;Z>hpO2yAZCwI)AyOJxMsjP#qFd;Nz4fKR1y93Qb&RffcH+7=5YYLUBoX@i!&ftgomV24Wb7e~W|uao=nxtvkI0gvp#mxV+FIaqZM1Aw{GT4{O-^ zum91xALzfR-x_)L;oX8Zh+4?&lV}z#o*-e8vC~vd333>2-mjs?KvJ}jl`h-ivsoj7 zM0p9qHKD`3OjF-AB*RobJ=M1iQnJ<&r(WsFi-6hFyiTue6nYB*%uJC_*e9+lDue3r?-ksJM&q+r zMSCKm4MVLhky=BBzdxc?S#!s31VbyXlY-g9VCgYeS9C2K6eNVkY0_&EL>fU`{M2bO zwYJlrt!Q=}f4~z_-x|uVH{Cb&QgvPxM0P)$#Yw}K;jn$DuSU_{Q5Af*V<^!GZ2VDi zwW~qcxlfcMC=SAqZZEE;gIs)kWPg-Jqz)R*spwkT*$kN^R?w&2cv@}xq|Q`DO&^N+ z9dMuAJ!(0qe%~UcFB>!B1Y@eF80>H(QZAnLQqf@%-rhvK^s!zQy4pPjT}8X{wu2?9 z46l@k!}`r9psawbBp}dGd97NZHR`2_DH}Fuf3%Eec>e;2j7^9Ts&->o05#v1i{^H zl6Ed;0OKh^YJ!df|%J`;pp2`3^3(WEE73iq}q4Wf$*b4^Yj@t!p3VT-$jdJV~8k z`0#~~+Ng>M9A!D0;^JJMyw4}10KSQ!5O5urRvguT^ymH45U0WjF!oC~^4)qzUxMj9 zb>ntD(8$8b2Z?_%%`tQJ>u^kLf1%r=3_ZosWYrZYf^W=h75)59=AGC@kUMs--R{3d z!SOk1lNduyD-GMRB+~89>+l`>vZeww!^H1INpdKo2I8^}KJ~@jrN(F6v=}^G$T;d_ zBCgd1O>(XVN)Rkhuu=qk8c{kFUJDFT=3!pj z1I}~Rt~9)SP6fv>yW*l6$dK)vjV>6w-s!iD?>SWgt(iQ(2I+WY0 zESF<>x3IK>Pac+Pd|Y3I8BKLkn()!j=26t;&TF4JbwzzNC7%YUWF6ADKk$6cbz5Lx z*w5p_dw>4r_=XID&sg4x{0%eOA_x;#fHJh)%|4g?S!^1|E~szjb=r4JceL;@iCNOX zLmHv!;u7nu1o(zK_dQqE(v8ORTi!Rh@zaZS#^=P^RLhJ`V^4rF%dV9c=vAURL&x>wCirZ_kw#n`e_6+|nJPl;hXW@Pj&m)YmNgBW-Z@|;K=VG|wqPKP2Z>mMrH+Z(tF z%*}tkdKT-EkjC-K$LZTA$+z$5@?ZHhp(Ve5S}gTB>}@ES@~x-WHPkw6M=$vr+R)#2 z3LaKixXTLZ$fl&O6X2Js)_A55iP+d%fLwPz=UQqFiaf5hMrIrP)bd<=rx9R?x^h&C+fq`3GRvPEod%1DXh`)?Ok z-6mgaUD--Lif^l%6#bB&f;1(%_}DMEzvp&8E9oGuLE9IE)wTRfO+yUvAUO={=~f*t z|2uBFR}~&4&+tx3G&AcCF^fR-OWi66%?UnalsQ0zL{0ap3T%|@R(Cwtxe_U3Svi=TU2>MZv z&<+hta``SKujcHZ@4Dx{_v6$LacSe2emgf1s-~|Qo$}YjOL+c$&oa@}CVfN%=MFCu z3%mHo>|}u~F2)$#E`A1M9nOjPhZ+)!Q^nEKeUhNhu&UrXr~Y=s2@T^`Te_8%m9Ir^ zFc^*q6+R0Z48gnC{Xj&N@J2l{V*j$B0)`(_VdJ$TWo7R*`g%8$FEa@$X)R{@Z1$w! zqEz++A#U0`8udFtO7dHOi!D!O7a8nKMD({k8fK`x1Bwo?to`z)`F#1I*CI1k81b+= z)RzJ3J=`VWN2U{=o78pUUomkcZ^4VVaPd43LKoU8ycOj`v2TF(UVP8IycIs9<2EgT`Kp_%yO zj9V@w6m=&~L>$Scd{)HFK~mSq$D!*k8#AF}%+jOfZpkDhJU6NXlZB*d6w7I*tG)Xs zDHi|C-oa6)=24{Hlugv=O}g8=YctiSxbNQ3kiDOqDz2%jXpz+58ePOLG08t;waHK< zPnXh+=W(;jK~YdszDCXzpJhBTRP{u))$=kIj%hw-9u5zF_fU8}3-!I@RaO|sxncF)o$Yx!%(Mc1R}uhnAB6caa!uN=jwtAMEIVraKZZJgb1Au`gnBny5{N}wOZ%L}77=DZYa9h%7BsATpm3%pkI6Kl(=Z)I@Qq?6 z`I}92c7d_85sJ6M`^{mx?XRf{-rBj5V7Q1@pgVj0g{u-p8}rrWT&AfGh?^Cl`_DlZ zVoDMi(h$2r8z@9=p0xf(snMC3CSY?r0t}j7x1Iky0Jj=Y;_7O9 zqEE?kB;iL9?$bA_zYzU_VO3A?>vbS`Z_i2bAEkGIj708})mV^U=3MX0`HNrN37CAs zov_O18e*E#YtruGEV&=2!7JZ=u7rp#xqB~l1F=&q+5g^{fHxG5Lt@{FGDsgE&ovKK z?zt+hQ`s&u7-h7K>)GO4yR7tcKEvI@kj?6WUo&|L8UxN7XkX4T=2ROp1!hhw@g{T+ZUycb1{Qxxi;3zY3kMhW1y z${ihUytL2raJ^QjHY$jP67Cw>Iww1cW{OSp{KsQso}Ck816Rx765(P)QGNgxF@3PL zlMNv;OhZ(jIAMr+how`Sr{p&KTFRj@VoXmt%L|5j>(iZk-+U%A>k)^&<*?$J znqi&Q>nw?J_mfm&rlBVLHU9U_(-7GS{qJU(U# zXBtHDpVRb5Rq94eyUe=QT5iQGd-NDxTkt4h#{N$+0`6PC*9%}G#) z??b3JC)pvkR!*6#_b7k8iTc$0a^qQ`&^x{U*3I>8YBFs{dLh{S{x6(5Joy({1?FA` zk`IR$RBjN(N-u7pM*QmZ0Dhgg|K;U&+gGwi6 z_9A*Ao@RP+lYHEm-on-bUqCl}c7OKB!ccfma*U@10CJFjt zSn1y*#1!*`g+&7beM9k5jzvms0(E%sV|)DVJ9cEeS)2wvP-D7xp4(>f+tM0&h(jT5RU{%pGj{-9#o+|2)A3<{gR+9YCI3X zm^;Lh;osvI=Zj%DgjnxaJToiX8NP(ovbLFIbMds84p~tc)B1GCA4#J>Gz%}yqZYqZ z@rd_01G#iUr;|6zB4afenw54f=Tdgw(hB-dMSx1$%Iy9~=&6Wyn=7sor{I>F4+@x& z2XoX({XP2jwyhIM;{@If~g=!_@$ zuV@r#6mO2%d>5`#c`Ljo{PZkbEVtGK*LhAJJ72u7dJ$Z{3{LgF|M6&ZU+NjtZa4pG z{RPy9#G+L*0gh(ONP_w%R7tSm#R!u8Dz8%1(8zS~*#%(nKx7#1eNtz9dj@vB% zUZ^mJ>eeSoglcD}F$#k1H^rl9$ivq)Cm<#AHiRX}2e#WQN5`mGJj+ z=|S7kD%Z_c)UT#PdceX_-NOdaoKSsDdtXT!eleR5rko>Ng?P@3NZBTjm)fG{k;ZguVN}25ia2 z4U{=VT<5b%bOV#APO6ppm6vjK!5h>U6fL7^tieMtdfXZ>Umz<<(siL7l33k z2o!e^zBJ)%ZQ-`^bY74y zh=;YC$=w}d6R;71RKJJC@p_~p_Gb6@CEuh)#7&9?vj-w%DI zD#2cTeE9e}p!NQzHceNb2rYaG=?JYN;O!Ws#xkjX6zh74rh?(x*(&ki9%i&img>qVW0wc@q~%LHV6ECWAGh5Slt*CLe_ zGeYmAN}}bq$SKMi03?MrPvtyn!Pwdm1cgq#>yP*co?$G^onXn}$~2?|#KiD_EbN-o z#Wh(V!ZrE}tR>YVG*7U-`9vRJ*drGb-lbH^6dv~cwPxKf1QXW%MI*)Ca>7;9CFAR+EaZneg-Wch_{TYBa%LXl})Jd=pH{ercO z1WnEMX=pgmCYCCGJl4@p!P+u22{OlA2YRObP5?kklIHrZ*e1o(C;XBX3gxiaO6cIN z;(&^dq_g~MqW_7vNl-vH1~g%E9E$WxPyyLeOdi*eU}v3;V-+Rsqd2Xp-90k;`GpJf zfC}kULn(c@Ga=Mrydkm|8Bm9DFGM$0r&d4yp&HS=@Zn4kzPyE4QLuwX#$^?sqrV1e zqgX}geCA|7ekNZ}`55^+b|+V#!x(hMBTV1lE=K*s87$= zY4NSp-!3G|0P3wJm;itMBZihPck9HR$6}fN=lPofj~>Yeb)lq;!ngD83c3(MISa!1 z7u-h;0rcH0zGDJYX$8@~Np9=Bl{f~4Sy5-H%-)zzFSF6M^0dcLqnCW!D3d%1c6NSv zFGCnhq>D4mnYw~|P}?jirgQ{%%Q-5zuAaG@AwtrgQ@?1W?Lo5c>s7%{@+Qc+$=Cn& z<^B&}!R;Ei?9?=p{*URFNATr=z|f~x6LSk6q}7xy$;fR>^J6G_Cb#3_Op~nBi3u(T zo*maBOr0w5J$+erz3zd3TYVqdWJTlnQuh4?Occ29BWn=QH)=oH4MB9ZX>ogbne@~i+& z!92J|ecEtGwnM&jkZtLjB4j*$xDiv=6T0$;!M!#&j&COn`0#xpR9(9}#}-fjpf`K%5gqEJ5m(jWI;WKAPHS(N2(NC5E? zPDL;FJNFBL+=p2*{Hv~Em1b$xEFDOC1;emOq zJL>3X=gu--Rh8E3BT8X%m>Z8RbMszrUZQeC^oDjsZOn56O`Nn(-8{=v!G{!yzwRyG z8QrzAIbI$HN}Anm`{TXieBPow1qJ$l!bP{6eFOThg;Y+d{@ngTNhu0gVFWwrNMe~G zY-1CVU-xoBuM-<{vUBldrVv@{ebke6=Q$1a#-C^>Cb_;gj6S3UYDV*;u}pVqUaI24 zq1-2(OQIoC{hud(cX21U@HuQHJH_b-l`$! z<&+OU*rLW4fFW}oYC2nPYyM~)14pAG1E6aK{6$5m=h=h*dJAU%mL0?JTKrphz5+Zy z<;z5kokR9Z#dfK}3GG10x70e(Cw5Zq0#tkwwvs#{p&?q`2d?ZBlT#Wv6OL9nF-<>S zMZT!aELnxGf%Xu>Od&V+*S!xH+?Va+yl2|~T+HUpUF;jjtYzE0&i!1Xwm2SjkogV+ zp-sMcz5eBbwULJt8672+lk)STsi!9>#Y8!vfYeS_g~h%vbdJ&aBr96-Jd(?zq#m%t zr)jfv5{LUj1TcXpzc~@*9^!T_ekh*iA-&eG_uT95Bgx$#y|10E#B0jQ-)EbcFH3E& zQ|$;cT`^7U9>EvE-Y*>yD!rTPX0FC-ZSDXLU`ixg3t7|k$A=y=Q#nlzcVkNgJEALk zzk>@i6ss{_{7nPamR>QS(U7!kogSzyGGvlI7m`>Y!E+iD&dYbbvHpfK?NtmdO;)0R zR(g=64~INO7g@{vs_t}zoM>qxH}XTkG|x#CiOj{~k<+0`VesqnfA!gp&zCmU!lQ{c~PykWytI; zNDl}eXj6TR7O@Koe7b6Fvuk{gQf0O7)=xG4eRUOwWx4e@%cqN{=z&8!D}V`ubXBFC zhrbEj^mo2)R$jiX|3j4_4mx@3woY*rq%2mUrWj(cnp>lgV6pXZXFZS!fr@vAXbIh| zXhz3|FX`U1tIsp`cdAS>mvYNn*urC>Jl5W0IWgmR@`!Qe)!boIKEi4MN z98Nh&#*3wn+WG8p?w^xW=i2|<*;GO?CdBZgW9-Uj?ie=;sotVavEC2PDiu}0J>e7) z_)$Hf78%2m{V6icl!Z=AcuxP5rqTP5@_|j-e@yl>H~zap`d|0Z!e6FA*q7N2HR+aH z%wyulG`W(GzVzrQ+6xQMX)E`#)raW+W?WlBMfI#?LD{x=2Gc|CZ_YX7Om>qP+5?D( z?{11^MlQb2!Ix9ip_g@B)AIBE_v?@6$KSi1vE2LB!bNbQWS_#@3cj8AP}}Y}Zc_xC zdr(jdrsK|5Tp*Dng%(@>a|LVc5e6yw^=2B*ddCotsFlMz&7p6=puWhkO+^0;IcQzE zQ$bo24d$qfP*>wWa4!Do!}Y-0Hn;gR$jDST$nzIP>~Db&b2Ekipr`)<^O(;QDo9Hz z3A(Dr*bW34hKGecPkg=AwS;((+A2mmUzYgf1wLNps?}bQ^$zUNc!!J%62Yu43^06C zy#HFg(q@3b>MVqrGmYZUs}=7Ta>{P8aeg>?E|(><_XL+8lpIu6wa4D9ocm6K2I2Du zTEE7qr~7sf1-k*9+CKN}0rfTt5=2W{!r#gR@*j!=EVk4YpqG2v9bdveNQ`|wPJbE0 zJo*+;{$<3Ns%nh>@gg`m6TaZ__GQ);Q=;n>&)^?x$N|FEaJn8GKW;C}*_t2Mc|krw$&3LEkLdDRuS9t{ny%-y*_ zx@7A&uj(_@&lohFGnI!qZp)}CD0;_NzFK3^P$&6MXu>O{^RCCukx$%hNefHHxBB$l z>guyAG3#v57wLzz6AIT7fl)m@cIs3qwg&`k$KKH5wd-xc!pvmmPo%h-1qd+@&$>KV zHFZ=yFJhf9yRlI5MTTI)BI!Q1vu#4*a_ zCv}ygh8fllw&D?P>_T&TyQ=$xE4z82UY@xIZYX&W%)J0#w#9_gQg`eAs@|1%K)JUon*IUw%~wlqpCzd|V6R zRtNVNRsoPwL&eso9-bNV9LtYyKMamZn4QYg^~>a73fRRADyt+R7r{RzEU~GtBJ!J_ zO)ROzJ4`Q+NCg(Lb4YwY{mtmNxZ=L|VPU_#cY1k|Adc}-Y!)QCBDz8MQFKRTZvL~0 z9ErbQsz?%kEAyaNil8sQw;6t6=6-RcW{Q#4#7!L;d`JXAmjhM5`|B>=1YLOloF9Bj zjX1e(`u+ZKCv`ilYf&ZAur>t`!O<1T+fWvmRV7g?Pk5GvRK;8Uf??noZDZ} zFG{w-HqEtfFMR8{*mDsS8#8Mo{|xsu>A;HdK-DgVp)V+}q2wmg;htx&xEw|>yEFJB z_Iz<{bFA#5HV54-UoVRnBoCXL)@jal?&}EHucMw%1Dy&Ip{nHJ z`)Q#nZy8FB>VC0Q#t=VKD())9Y-)YSV_etmV{_dh&w5-U+=)JEoW@Mj@1gsy(0b(C zXlDOeQLQ0O-S_ex1irwsC>HxY;7ap-C)n%iI`z8$uZ<2{#iV9ARFL<<4+f|m$Skm~ zeepd$dDzId?pF9R;y~@j$&H8)#~WH$G9+RM^@eD2HS{-Tx9CShflL@psya8*TW&G$3f+ zYo@A=ZKm=x!W~~;Dehwi6S2JgRz4%`&tC*`kvyhF4Uey|J0K0MPkgRn;OV*02Waym zR<=}4JcX$UF4L~6N#Q3LKG010(;T8Dd#eSz7sZypuV(I0oe7dM99ii6*yBvRWr1_) zts`6tqNM>Q>a$yaboumj&as&m6J8Vf_radBgM{YigS_ei zGYLlPZ`Gz+QYE=j76yV#SCdrtXGJd^Z#N|t+_ScJ{=j{ws?YAJdT1+k#mAUQ=!u7E zd3>)opM5Orw!4mA4^L(dYHN$sgJV)05gkDJD05WaBB{Z|&ri}Fti)aG(KUooOpF^s zl&&svIBrc=(gOFwJ$BH21gC@jy;Y8P ziUO?@Don(`Wx6O;#p2cvDcCgWbn9?WNIfzy6@m4LBzow9N-&rDUGn%lKs=Vx@ken{L;5Yn9GA?e^`o#K$Pt{yWB|d2CdDg$k9XVS>k!{dFYe6jNr^uN}pUkcWaXsvrb-8Whn=U z&h=?ZJ%I}#o{Q)IYwN4SqUyT#RX}M8>5}doKw455BpkYtZjf$}20^-pl!l>18UaDN zVMyt21f)UWcSfK0dB5-aeb+VD`Df;w*=Oyw*Iseod(C_^zHqHdoOW&BwiKbf%_OnE z>v{;u1pH8cIv5|{yRBPNN4-fv$LT+(pl!jVmai-<6KMA8fuBmVVqYSqty8>0WZ7b^Ku?``mlj zwr3A*WeUG)xze z?e*#`7-ES^s^4SuSiHH_@Or0ST3IL#S~`~A$_?vG!2Iq#`K99@K&0doB zwgCZ-u2Drb)%BBaAt~b!2)8^zEW0AsYE^0fYndB49wFkeGN;HTrF=WR)4cOvQc6K02ckKb*~~; zJ|JGlgTszSl;;8MOKS+48qT2RP1>`7t%U)3>N`#LqdPaM)Hy~Py1HkcW_Ff4#NzHF zI8Ah3*Rsg^3sRPQfi$9gHFKx@O#kp~jm{Dz;qCGN7eE0AN;OwdrQf#P3^Ny|Yjtofaqj z^N!`g(|y$Lysyg35u);x*?o&RBCVV*VmBT6l_4ut`qY;*99R(rc9Mk#K%1#@#|QV$ z(L4!vOJe!&9lglx>w7i(6|g4LpsJJ5S#4wQ0txJ&j!f;|)U{l3KdB5BV&d%ubsiIJ zlT&6F+DOl0f6OcK$0S(D>$N6(r8V>*dehy=-I(=`ST8JFDA^=WJHV-2VLb3kF8e;h zggKhP-J~MS;(vS60B{Ns${s$mW*+I2BXkO9xvx3*p+?ROS(LaGn2R_+oQ0udvWRbQLi(vCO(exR)U>2Wva?*!&yz!QKa8Es;2zJkt(wWz+%eRe=;^jSK*Zjqxm;!mixGSesC|Se&#`uzcMkYq@SBmMs%u#-A&P|Ui|aqrz5S{ z`8`D}>ekBB^S6S(3w)uv5kl-@1n3)$dN~QZH{RZ{J}fGzMzGO?pSyZ-H=g`EyQFR0 zm6*-v(Lp$AbAF!Ua*B9RUgT|AKcVP|*2%(-&!-n>>~S9Y&LO8#y;fO` zM^{bZC8l~EkR^r3Yr9%C&PI9<$Lu<6J?;>75MI3|8hq}pK$Qa4yQ;zEzwJgQ%gSa3 zDN=jS5~nYH4v3az2o1HsFmCk0#Kxt++`0D(=Xd^rkt}I291no2U>+N&rr#1gu8zJp zOA=(dop=rzT>C|&*g76o;2`HugQtB?%r*x?i8Rbx-5*1*exMf*X2`qkafzXqbnqwW z?cBkP#8rWIv+|bmmgXzyLFDsxhEXq&Y>r%Q@v-S^B^e8_no5es;>E;LX95o#hb{$R zxDJn}SGh0H=Y{z8WevS3*JPv%!4Id>30A2qS&-F7?r(xj3(a3WspFsl)e8ZXU zW8BGn?beUP-*1R z6X9M1_tX)x=-Asa2=V6OoKRC|m&*k5SNxFf|#(x6`~;Zm~cmMX$OY`O5Z>aw#Qd1rtLq)Phu$Vi;N zLQOfq_J+CloL<6>OQtW2j(hAkR;5$^3oK)w;Yhx+RB_wP(_2RCkWoEl_RaBxA@!s* zRrNHXA6k{!L5Ogw{qL4)rlk9oFq+6jK1H7u59RUZ6X8AQN@h|LQI6bepBp9NXrnb0n; zcxYiF!)LCb#S?V6+ddNt3QsD_E1n&+I!oCtj2TH73klUmf1TAr1q*5}kG{?9#lOql z9Tm3=yQG9Qr0e9xm|Cc7bN?14@8TjSJ(v1k@tpNGgY~#LEs-I7PIp^*Kq0;&Qjw}i zLXf#A_ibUda*e4f!J5kW7qFU&wssKipUEr>@Nw!DC$`%!dH@& zYx3BACa~v)XENaH;qpNJk0lPf0o4wKi&yg$_qV~6fF~$sdvoPymVPBQ+pva9F@G1% zZ=Yyy=>F|-MY5Rx#)5T2V1q0YnSXh}fL}Rt>_QRBkK0+T`}h1D-fy0eQH^yJ_MBEl zgxCe9oIX*f}{{Aa11_@S|)`H>$vb(hbO7;zHDKQH@X_Y=sm+jLC3^<7rR%qP;E z2*Thsf&26}^lGkGyJOV}P=BY?r+tId^aiy(LEhhSVj(fqSNqcfwYeBErLy1)*U){3 zir8CUd225~miPEk${E#h>T>{PLs@$c$Dn?Ia8>2Js*{mgJ_l@ka<8;}y)bs!R*Kr^ zI=~1@*n4u6Wr)HdoQnBl+A;P(>DeRI&#Fx=!f2IViL{MII3G~_60tslW5&4NFN~cv zEY;!c$r)2BsA^a#ffcDi)ty3VY6Z-yBO)KWF?o~JGx~3~#0yz-Qu4}r>7Z8mu)&N# z7$258LAp@mWsWb&#P}R!;f4RLSsJVrR6xN~sshk`k|v?SA;FHg{N&6Xcc<7c{V5kC zp7L|3S=ctA`*J9zbxE;;8d7d$uh77XDgO(AR1XDVc9a3VAa60u-HFhhcyI`p=~<9V zTr&zYRSP~9+))FWj!#X^ri)Dv$5KaF#&hiigU$9cw& z!;72s%9?5_>va{d7{}xfe(`RHwSLQgPGly7GQMZ4k@!qLdqC<}36qEXjZALrY%>6F zmO0xUROnN{2jX$dH=Sty+_4rCM!a0lr^@r&rRh|6^x(%FggS@trGV0%@ zUHnbbBj*LFCM`xgGgUdN0m?~DB~JfYR8299z&!)ro~h|F$2~(^$1Pp#%d3|Z$Nd!# z$kB#n?eZ^krlp1fRa*fBJixz2iGFa~sEFaU*assTXC^W_)@w1#6^!}-%HD*NB=59<5~ zgUhp@7!7`5u~O=4l5L3O&k^eP}<6A5{J|ugXsOnf(uI)uZtQWqTvN94RVo%zi=-03Zn=4W07k=S! z&a`^SpGLGQKR{zErWd7aD}O}$Rps|DEkUtxTS4sZI~tNqLKxq;@8Y@mCV%h;+D) zRBfg)79{Qb=ho)?^#&&13AM`YIy)G7G$vXb?hd(%nZpgu*1KABOAk!GGkpPE-O$^q zqNAdbmZM9m@}nhXlI7?g7stJ|rkV2wN_&Xo3BFguF}TCZK7Qs`6mEt8l-B1fl87Z@ zlK~9#hBH2!-$5oJL=K>5JGmK>I5lO`kdtt^tJIRaO zUC263VX=B}^sru)eOGYLy-xQUQni4OsU!M*T7)ajovXl3#$_7|?qO<=lcrp-3#(eC@8qdNV^clHU<03>!fPAw=jI>5|RU+D4rXRuXU zSXP%uPx*uUt>iG}`IF9rZ%xmZLHBq9MSLG_b)sXrDt^XwFxOLLXB4;3iEUhReYQ?> z|IKn-;ZI*St_vAw?OBhH;fu(^MS<&vzJ)FX_=ilbRGD;L26%Gt@0b|{DG^TXZG>x_ zxOzFqiq$WQf9KMSfKc)iZ(;DKt*_|-fDTc;VBrJ#ca=6MSx2z%7;p71IjjnKPEH%X+ ziw}n~voX+;@u=9>*9S+_Vz^h@CH+WkeiD}N)I_f*isVOZEGo(7RA0P?Btd}+P|z)g zX5iR+GT4KUq9kmTVU#hmizTub_j;!0HmX6zB77n>h^dGhu4`22;~<(#I$4#X4L})& zV6t9d)(?AMAxmQK19F@Vojz4NAa`Mj=IVeNYt(CUijs#vHS6b^;LZ}!HJ0fsa2NIW zSL9TACWQt4a!lmCpl!@W>Vw}Vun5Iz{Rj#Ez>yJeZ!zJLry-P;6IW&CDf)_Ft$3GQ zQeK}5&nDj_i84DY$i7GYBD@x;pJGR|DVu>Pezt83z`kzCIgm?B>VMOca{eH_vzCAD zm*|dd@@{{hl`#DYft(#_prO@^LAY)eZPP<4Kv56dYcGQg`3!zlbUM&yUBEgq7S%n} zujlt3PI`bE9^Ye@bbMtbJCg9o!%14|~Y+f zP_T;CeR|llSY@^f-JXI7Kh$!AU+L7KyJkZvSGOiYJ=BlHi7;vzI}wpIpEujmU)GEUHC=4`-fk?N{7?ifiI0sYdm)_B>ooi^y(Dk?`r|3 z6#wrA;%+H|NV+Ra#et^XUq8NG#`Ht0?5eHaSx8C-1!W(*kdRF83 zD{mj%zYic+^mj)2U`Fc{2`S!I#`)ab4<$JTQn`FiQ6fd6iNkCmF^$ysUEzN@Axy^jz#(sq_eSL2`ip%yS%_Z6;1*ji5+K*FJ zG7`n26=0GIUhH_zWU&x<;O~C7#7URj!m20i`clN?$#=F@0oth zhT<*>gva)aT_&HmseaGPf3j%Sf(n2PzZ6o9xgyC~lS=CBp?;Z_eFNZgq?VYPLJ5c= zQ6|P8@3`0Z@I$o=coI0sw?2G6UsMa;5JQexS7g)D(AyyG%VK}0JR83L>w=r#Z?g_P z8G1r%YMyqw#eOBU;c3RfLC2$7m@f(*+FMET5zRem{9Cvo5~8~=mK^W-p;7h}Y`3Jw zE?93J>v!koR)h9Xu6$ap%X7X*y$0DGoL$ro(s*p0YbGMnON1!#oz2ss3IoLqwkV93 z-1;RYU+>9ws@%{Xg7@Ai4PFgh>rD^l?{+0fh)J5lKWD5h_VatdC<}T>xA!u!e3ekZ z($?cyH#6fl=GH&kjdVaKH2n(bif@Y0b!Iu^J9~T=f}a;!Yg@l`udNl=uwEsh+LA2% zRw-MSvh&uAiN%|255`G0LaZAZX&GLf- z>&Jj#_9z{2vU?H#&$}_S(~?hfLGZ26ZBa&UmW42(7OR=jf?pM@2-!{oxN1{|TIiO@ zBX@g{p^>_cZlSJY3DA;t-*?A2j1|<#<9yKk%{TvICvj8_$khA;rzE1TA*3r;mn(;> z^~oAXJYE~b>id#WW6Hh%%K2jJU46Zzn@&7XjCfU6u;Vg=+(^QlYkZR7ccsB3P38g= zGXtA5x|(7pyp-UTOq@0bd&hdv9oPNh;#EBbb8IZEWi{#WST8zWB+<;SwCt^fBsHku z{na%@Qb|o(BH_JWf{vNDdT5ysKLv34TCQby z=PZpo;3OzYrI9I0?_Z2EZT%xv~^+C2Ls6ijUz6Vk%XWpvSCSjjJcTS7!mA4DY|E2;Cs^A3_j9I?BwU;FpX9AGjfX0z4v7ebri* zWvxvr3M?Uro3rSKPQ2QXwzfvI zCEpg*iF%caUcb8xmH#_?T-{zsjiU&?luzFh zQ0J*V5~+t~mkypPe^V7=qziX2=MbuIW85HgoJ*H$Br)jI#YwtIJJn%dFzB}1L_n-N zN&J=ILWz6?1;)7o>Vola^IV^oDEe&DBcqKZ7kY6Yg)+D&?0?~&eC4FK-rTpKii@QC z;g?Kg}>s)D()mZjmGGd^zbbJ}aE3U{+F%@x@s-hIHjV>G;p5&7h6+6Nu`w z4GRozVUSc1Qm@kMV1VPx9kHNds7NlW>^^<^o=k`c)V1^JR5ZjB`mTyEZ0aZH+rnDq zGFEWU_`+lWH=Y&jW?XFSDyQ}(fUy~+KG>U=kS5YK2MQRa71Cg%ic|(=^}8lc)LSY|>JqF8x7FZmVId8<^sCPLMujv7pV=032 zMpvEQ3c=@&;f=lP6UEe;G_qczP6aW}HrO;@y{P)r$hix(ym|=`=~o2eLajCx;2g;+ z*2tikX?=R}MP(HN(P0W*1UOshS29UaMiPskxyM6Rawxb|mLlGA5*^nTFc>6YVjMe% zRb6vHR*JtK+E7d7Nd*O$>75>~jX`zV$WZ=gMW(hNT{=k(3g?Mn^68-ND?eNf?)kf?*ao z?+!OY&fVLFuKU%e8YU{&NdowV#s}a2l=F{;&@hzi=j_yO2CkM;c6>esYoE62CxpWj z;J0!<9MACLYLbidYU7B-rR{)2Iz1z^N;kWK_3@=5XKPJZjHuRc+ z+YE64B~Zr_qBrF^Ad;x$j8MR^S}G>Uf@y+O@ihh?JSW|kmV#Q!L0q&(1uLujSKbM1 zk+zBffh7>2B^0gr-|B^EU-Owj`?SXo{r|jNu_b zNq8{Hdz%g;1-tA3z6a(Z+K~VQa=Kn?jT$K>sYyv>uNqHx@pl4fVoL4O-CV5P~ zN@3}l^a{Ke-}NruTQa&=SL5w5#7EIRd>v!O;+q-FSW6wlKI)}#|5=!8G_0nRn4E7C zS8`Iz_l51yY3JG~_p1=(;e<#vM=(K-+K!wt#Ni$R?bH|H1glxQpT~ak&6kj)o3*qX zO=xf3w$5G<6<3dQq12pw&6e?r=E*zz+jcysmlzRZYvLd{YZc39P6 zq<_STgo^7=uXtX4F}gO@GIn{MG-P%Pq?T@EuoA47ZpD@{Go>>Xb;o=5+lg1<0Erhx zG0oIK->Wij`8~5=iT2oGC%$2o%EadC0}8`B*#BJqswv$)z^|09r7RZ&uSQMP=I@Hc z8}L2|1KOnxi%}oTF~DO}VP94~RXd2#6)7v3INoQc2Nl~+EL?m{#cowoFT89$cBJ0H zGx^^2oRqX%ioKgo4P2ml;rUFDOpVXD=kpyKj)N!VNY-|rIOv$smc*4A*Yg=oKKr}L(5e%@ z3Po;{nKh)c&>hQC&UMMb#KJ;{D2#W;Xp>R*4uETBISFBY1^wz|APQ>DlP~aK>8!KV zpxfRd1zdPaXIXhkg=Kw_vsH!j0}VL$=-we`ixTtkn6ba6{4=;WlPI^6T5)_Y2m9b! zBsn0n7KF?Il8QwL;==wPT;)#-`dU2IQa5TFNpZXr2u-F1A9l6I1h3^WnMkY&+hxIG&P? zRJc92I7E(*tiV-F{R5IFzU2bh&S3|m$M8>dO-~O%wTI(g1sEX!n(FMuPBX;S+7nFe z<=sRm%7K@nb_GpIVqp;g$HUWdt78ISsyAa=nyd#>b;ZdAZgxVCVRRocUIy&f&;i@@ zhuiClpy<|^QJoSs!Pj_DgUZcrq1Iktoi2GJHZ3i4Ck;#BGUfD#D#dfMFO?KaS7q6N zrM>~daPbAu4*2m?YWaNhJ2n7JQc#owEKbT{YEyxsTHXSnp9!4oD{OV0mY$(gBkf$x z&FM(1Gum0{_d~9F1*uqlpMq85{mO?FC5Ks17NNQ@s|K9%f**^p*{3_)O+vGy05d+? zwd&j=KB&fRYhv947Ot;A3^y6&9)CbT%jq?LeB8AG^evPPnaJ;9BxzD3tMf6HmeY@K zbHPNWKmyNH3qBzds##=IKY_O~$A5OI5G2Rmy1_Qg25Pnn!{}Iu6*C+X3-v>w4YX-_ zPHwIR=YLGG6uuv)bJk&vFAPrz*0UC;4g(Ru9#m8?1*NwTke6dZbYg{V(1rhXYyfnn zb`Ih)fWTP-<={v%7)ySgZCaFKkiR9KmxR*h2Wz9vvi&!EFUvKp9ZH@mKd~9h8Ue&i zM1$D6*g%4;yuigqaNd0Q?*s6Z0e8Dg2MPdhI&q#`>u{=Mukb=3aff@w`OSBz8i z$z`w>c__4L3g}2#bp~EwSzL3O<8!3w*R|ym%V{glHO!6C?ucT3{G4h}#;=8PK7k*6 z7{uOxA=9rhd1Hd{cMJ84At51o<)Yq+$W!4ZnsWOk6?#U?Q2c3}pn{(y1=4?xn1$ns4;r?noDZ-Y&>o@sp3}cR21@juK zDA$@7S;9IR#s9drV@c5TqAmt?&PKZ4#k8IU65!#W9D~cO*6oa!XW-L@hqS& zQm0dlTSYkM^$V6#Uezh%0d87TrLqIo6*@5;p5YaItj9WF-PSM_Ja5bXMkRKDF{EQfZ}jL4t)pza ze~=yKx^C%xyCdJir(fm1qh7=;v-uHrzQ+!N@lL~L(qYYC4Z;)SR`|%7P2`jVqQr?&~2bPUaDHSc=0={VSRS6D?6Zk zoF`jnScXsNuL3&>u=40r9H0XJN9aABbhfm+#gpu3*kR5R9f*i75FptzFHr@z==R@nOg-DO=(s8_(E@=uS+Vl+oc>y;f415` zPy90s^5J+0(=)l(Q6V2ouphN#Kn!(5j*lJ1xDmGO-(L@=B|`t2LIrFKD34%7>msFe z2=emhI0ghpHOBMuDX{d25lion$^FmB!>TR23D9{bG}@Qeh@;aiX=$&X{n716LO{3w zNC9!g48lcn5{P^y#zQmJ>rz$KR@K1(pkO!t=!(wYjqeXL7+|*n&tG9n3%C>OlnHJd z{{8^qwHdc400DfX*8lbQ2yW~C#v=r`HIz!$!kg@mc*hX2{(lDfSG*SO0BPt`YayP! zTk^Xa9!Wn9($KKSe`fA~4Aw^FFPQ*nLXxO<4ovu*- z3>@;WUc~zqh(37mFaRtqq4uwiShPn)M}2CkB>}=tOB?&n&Q9e2-d2stGtPOyk5D}> z;P4UyjQc1m1gYiEyJSH#GCCV11F9f`&)~@jEq6o6eOT2TJEpGf#Ti2bqapUldMSNH zfNXyf{9Fe@(g~ccp=VhU;@!`1S-21i(|FOkZ1m@8!0iGyOo*LyOBX6Q8=4@fyy~&p zB9L|VTnXpLMdZQp{u5v(Q!$2vP=}jzuYdgJB^6RWLV1cH)Brv~SckS0LV|+IP(g0) z4;6RhE~jRns$agQQKgZx6-L||DcyAWgNAm-=Afj|d2p#Di1f&xX=|nmt z^eUZDLk;C$!E^3C_ulu$`ypdw0NH!3HP>9<{N^|3=A*Kr49O*$OArWzME2P z3j_rptlj?#Cld!;$)fnUuvd^xo}lyTQ@=|3|petHji zc+4L>%FgVd|3FK(E1(6zJRvaeQEMU{=2E*QFwgRkCghF%S7nx95yEKFNV#-X)({ae zRrZj`q6=VRkT0J?iY~mGdKhbJaFswhLp4-Msq4`W3k32_;TICD;D`1nBLWEIRY7Yp z_%xS>Aq>1lvlX+0w_oHiidn^EBHniIaw{RNT-0T@T<&HX@D~;vLs*}FUcb>NGaKvz z$%GeLh|lGgi}YE@4;4Ef*cTxKsWuDr=aI7fma~IktXIE~G@+Ua<%Vr<(Yir98y~-y z&}x+~eG&EY4h})wt<6z>7Z{N`Em3qM{gTweSoPx3K|XdpdSRCLzMy+u8DcQ96p1cm zzDo1G%6#Dd&W=Ic!~H|Fo)VdMe*aO_lVqZ?iVfAij4e94hS4!*$JLsZUomMCY)`TG zxmm?Y^$nn7_DBJUw_x9T(abm}Nx}Jyq-@jMlcEc=3%Er@VwVE_|V@>UjRkT^mI7@s^ zB5i76YrW~MeVHwKRgOyVBi*{h(VG3w^GUk`j;6m59woI$Wf}?!@jGgCyIP;$p4A|s zJ8<_r{2~v(UF}4?(mgd2M41#Smm<0N{AjDIlwQP}>fu791v*2!`jOF(H^yUCUMCYL zx@bGqs++2^Ylcr6qjV9m@ghRpB3|R236eIWuKfCq2WPYp*sZQL87U0agS)QVODDf# zwgPt2-@W^S*3&y2br5A%d^d&=a_CLlVenj+*Vax6H8>A}7=7(Feb`LzXLP-8m@_&h zKK`fmcg{K&WXTS5jM;b#m3y@4pyl-STEC)BH9$rX*&S zZUw7xJ(+5_n5$00QtGhy+-bEY&uYXyRi?bZj9t6J=HwVzceGQKHx=oq47N!sJ?|A|hJp zD)%Gh#x7iiKpg99@}_F`^h>>u)U8LHA2BhN{7S&C9;J*vb6yob8TWXGtdTJrtG+;S z2>e0XV^_D=2$+{nnCfJ;I^GiHfF$oWMW-gy4D82D74ju6WO`{e+J zWBYl<*t$BI$B)z1^Ormi%-A$EE{q9f>yGKHdaq3=?QS_lR7Zw-dPVws*Z7F(z)8|& zw%4cb=;@(-In;70M3HL{DRP{mV)QqomQaTh6Bl#TuR41p6E-#}b@k9xgO~MA-zg*R zlLa0gX6jjt)+OoYqJkypG-3DS<5#f!mJoI|}9jMU>X-0d8b^`$0sa^a*e`r zsP-t{xzY=FkgHA?v6^g&BPV>_@czX)A8?KomQhYlL(1-|g|(UneHne{v>sUt9}QdZ zBDo}Bd3j|18Eur%alPJlf5(OO(YX$j_Seb~$k!)^um-bX$7A1fMa+t$zgm?|Oy(2C zd`u4aCOmd5wQUosoDk~yf>CjC(A;@&oG#NJE`PkiS5jUDj&304lI)tj^C{+_iqD+?pyQz+nM)Ov~=0bG5ylMfe&%*7kR-E{CB)tZSybY zk$Wp%WK^NqFAUB?a=6iJ6EMDWvGAPyNtxp7?lW&xG2rIw@0eHv09 z{uNT~82mPyq;^S@aI@3X`YUfie0>`YKL>%lsl1J(iNPkE$QL`zyD=oSri?`OUjcvq z)LLw8w)xvCSK}nplt5Az0|ue^$ZiqUnN-(T<7PEB0)jOAbr|X^b{pfPsackgP`di} zhdkxs$1}6MZ6iXP5lSc%quCE3{wjq#GXA$!wNac;%jaijyJAbL)$^%AaJz6tJ2Ej* z$2MYrYxe-BSW4 ztQUR1S)jQ@R>=TC;c`{?y=7{UD{)N|d++S=G5xTA+TBQRmxSmX}ul^bK+#b_lp)1H#+&dQu3AwQ<-D%&Xq`1Ka030#d&i2JO2&cf=Frt?RgZrF_ z3^z0^QeU_T_P{p_&Re^_-cfFoyE-aMe0Ab*+(TU7AmW}kG36?(>u^WGo7_E0YouJl0=%!a0%Hhvs0}GpWr#z6N>)*3;Vbn-8w@(9#0-pc~6yls~w) zjYfzbyLSAFsW$IlkLJnTI@q=|8kxy@&Os=?&~F9`KRcSl`IeSTCei;n-f8%Ya?_{15(Y1nPC&DwU?Oa@Rd_A~Z zXCZF_{n#z=WbmWMecL$Tkgrg{@jg~6fLpxxOI&Es4(&Cgm0yJ`3HY`l)5dYT7I>*ELrTm_B8t>HsJz&}mqmNE%2- z65o-|gYNYv`RE?)&G6P83uftxKy^Y31`F<9fswxZ5C3!=0?W>7ZJ(tso1W3SC0tpN zGuV4(BVDu9cx6=JyR{BfoRm|$V&rT6O3F2!JCYa-UCbwLrI8fncXHZg>9_-_5wKKR zz6`b8IZh%8EppY~a0NHNWwLClevuo$Mb!X3{y}qZDqS zfV|l>Fjyf_B|2B4nYIybJXG|s+z z7cjgtj?lnjaJ}HL^2RRw{ypShrouwz?|chUo0@6`XhBU^;Rnn}faUn1o#F2?hxt`u zc`+us;t#T3APfpE8HMEO)xm!@@J&=kM14uSM2vejk{FY{v!gC3Fa%tHl2wzOu)eFy zY8h4H=C&_bFi}x75l9|DT%dP8G_;I>AW}VVVWRG&-FK_hKGLxjY`6U5Veb57Kvo(TzKFRhpgum^gc zJqB%`&z6-bp`ngqgkx8eotCR^-Kv+GDPENmGz53AY~L7$9_^SpC)QjPewmvxGYkb- ze|76mZZp~f=}JpGAiS4G0C__YZnUA$ng;;pLl!r<6c5eQKCM-mZ}XnDck_T>Jp4Ne zLa}qV0Dxc&HzEnX43ev_GKR1_FIXfD^rx55NwW)76lC8gf44m;5`jW}PInV$YRGyT)R07^cbmZk&30Vz#3SBqNZqh90B*ZXBgfHGjd2|@wpE@NNoEiutSW2NcS)MbDkG4y$<`%-=2kgUI~ zft@;|e~FB+zO7AB>umU6u|`l`U1d#rYp%38cqkeUuX9;r0{q&$cCJ5Lt0NA5o$%Iu z+1a(VTLtQ=?`2dz=S;rmwQ#4vSoNeFSzCt+xg^qZeT@md@N(rA*|1acv%oQ4;AiX^ zaYpCFm08GWLheDKT{oFclemM>d5inI6R9G?@p4PrsXeAHuPrQe>S}j~OPOi;3UYdg zEYOLj-9K7TC{0pAkOaJYM`maL@YYmvVPUbdn3T{&tye2%Bu72J_VT4opH+dR2MiJe zIVUB{DFMoJi6B%yxtDOQi6|~9$!6s(mH5-A>oN@amG-mV&d#g#ej7Sf>}-2ENl7Ds z4Qy>D*75*{iGN_Eb#nX+w`(Jaccz!>r0?iO&NKjYsLikP(juqW(F&svksm7s*aFfR zaGrs46;GDx+ix%Ls<`gW3Ayxs{;c}?bzNj716cRxXz{248;(Ldat4Vz%)um?Dn~w5S6rhuB|yE(TkwM_#FmO8bJXcwn3W(8DgqF^aq{gBeLf z7efx%;l012@h?W?1E|Goxty0QBY+Tmz0I@8E*}ES4Y?cb7?sb@d!B;pf*C;o_{FbK zYD1WOESzZ_{CVM%tjSQIvcXp%gb-+GvrsvMAoEX#mQ?1oy=1Vx)M0N+h0f^E*w|)PGvBbhNp`w}iGCPoSX_dXZ%iLv+E;t4^FU44(Zcdb13?AW1svOGODT&SO#$C>GFT4R%c3wSl_vVNB>ss>D+JYH6;q0D?BM^;w0 z+ld(3;t6*6NfW9SkLI)uTgKv;|5HaP$dX-&PZ|00S z`JFE*rHeXHkA9H&ni%qUKl^c)98glGpA=4!|1vC26jCn9FiDP@X|V}qsM{Ybio1V5 z#$We(Uos<+qN4Ng@EfZUiMg&YIuZ8LZCzXdVF3zR z_-dv2*`!${?vihKTwI;?SlhKbD2ozH35h`di?IMf(*tt{7nYYbzaAwQuAL|_QP3%6 z2Yjv0Q9Cg~OW~jnT_6~%!~js3Db>@bmy?w(Dl0>2B)Lz`&zCtZ4~5btm6UNB&GGZR zz+mzn?TdrLltMoYs+f0SMtpdT6>{e~EP%cde7Q6;Gh!zlF!>43KKW$jcL6r5=ryLI zBAKwqMIiiq`!?Z@HOu4s914G5WoU?psXHFEmu9?0$rekaOY)Ye9SO&{U#kVq&$?pJQ z1uwmn{H#?O^xzNO36t$YE+LwKY|_^Pm{I-|EHz*PIcDN{o#pF@QOvURYT?xRf6%{|1Er?mH2k#j~mguT-{*{d@CwT5d2~JFo2N z0KIet({lbC$A^y}`wB|jw~O4jjRp9FE&Aqi_x22np67QGlZ-9Q+*riWRl06?TZsWy zSz?SSP_uX+(9#Ix&-6?axL}%|kI2R*l2}Kl1)V2wgj+jddt_{w6>vpo8C*JZL%?#d z>X(8O@Ga$c&5ex%g<{AaZgv*a`nHIV!_Ibec5gj_4%q(da&aD02Xd*vV|VSsWum~a zq|dPjFh|GoNVYIjz2R?D{ZSmZ+S*D+N^`{=7c`6PI^)OSoMS@X!YkOt4cv|ns^I4T zfn_Zod2ckmjp1?O(Cp{9Z`K@2CwaU-A3G@Ow6v3US4~@cuPtH<2pLbLF#WSEs62sM z3-mYKu8Gs)=Fbn;mYbwQ?rGK-z$<=?RfCi~CI)+Cgj|GOeBV`kE|b0#*-NdMtQ;@m zQ4PEW=up0XXT5P41C0DK+J})dm}WqK?w8K=rji)lSeexakoYnZ0p}h1zW9Bx)^eym zUrW*)g(V|=-5KB65zF!NdsbYdH^}M>VLabpJU)0rwhpVUDIBD~aibih;Cgx*;-nPp zuH^2}BH9RuzW$9G51GaSQ=?gr;la6;UBvNIKRLN%d zLNNFC_S!o*AZ>(imue<_`t*F<;~L@AR71ddem@gqV`CGz?zQ9K&CN|!)&y_3hcv~G z3nLR#IyN$q+UG($Bfx7Oo)YXf{wHNcyoq0gyp`3#4WxaX0Lephu-W#ccr%C|-!cCK zkn=NKvHwWqWS&^|6o|cg+#Ssw7sat`U}C~!H@!Bz6COSpCaSr$Kd+Oc<{;*MI2SKa z&1XZ;&YjrZ9mU{Y*oA9U^tCYUE5x{bnXu+`df$g) zV&(Z-T>t^%OG{-bt!RVtCW#?jcH}0j&Fcz+(qF*5ugx0;QBZjvITb#OQ`E>I>nRvR zA06-xl!a0EnXitDM6xMu?k1Jl&16SMUv2uIWbtYBapOnK5_;ErF?}Cevkr@Uv~6ig z?^B#AU258s;+(071cf2*&9(z^KiyCCQ-EzYhxs`CZlz*KYO@;gPEYs>^xBt|#SX6~ zYkvH21F1q^h7-#+X&RvQMtkc{&dvsvVF3A9N?Pie7Iv4#HsE0)x z{bpL51p{q~hUnYsVd;B+7)d%wXmJ3D@$_eC2)dJzg)iKA9$2<@E zB?Ah!0oC02c=M5^j&X)&)k$7n{HHqxo}RZ6HTO8QE0pRk;3JG4n8>!S!7HrWkUnO_ zWxqdr187B{CfEfkRb^iP%|4r&>;3e!%2vKsfP&wUhHmy026MXyT!qI9a3QnO`-zHA z*U3v?RGs`6rR?2G26fSeNa|5N)S1LcHjao}#bAof2YPlVu6`bOQcxHLDwU^~&N=aypyCxuR~IK# zUh?Fm?$F+IzB76H07#=_#j_J80=A}=RaG<|L~jJ9o+m*Z4bQ_+XUs2uFH%b;;&3k~ z@bS5dkRV7i*qaH{12w>0P)Q3PcT)K*H{ugQ zLoX}Kx_C^S4_)RWcnocX&O#nj0!y+z4H5ra9OV~hBa&DfXS=6pS#3RbVRbbWu+7B8 zYs1?hfx2*cudSnFD#0bu#lDzrF!GOV+ChwhW(nt-l%}i^LW|3PX~z#;TO`<7xW=;MgDYcYUn!>-p^@L6D4dW7 zw_F>Qm6ucT_dinSyl@%9MB3E_(zfn|KiL(>j@|kCdIAz!Z&X%~HUOg5)*bzsK=LDI z#Y3I!%RXBjg;ma0s-_XZUtVMv50~X@WE}-T-PvLGKTytjWvqPvMcGV)?Btik9u#|l z^x*AV2U_0Pkzyk{#7$nv!qfN~MlkZ&%$C1*?n+Z%w>as*tG{~zN_K}bm6A#Uk%N_F zC?$y=P{F%Fp~Yz#m9JA>rctQtzNq{&f-m`ti5baQHuae^8U=fPPNm%j_K zE)8I&62!fwBhm92&KS7%l`Au3my-4BGMed$APdx>67oCekTMy zFv7vdSzAl4V*!9XQvdRBx`5y%6=005c!KCF%tioVoCcDdJs|m|X*6ds=ncr56d=F- zxlkhHt;Dq|(;iW1p)63IQ>Cq1J39wzzyA+UEHdlcuXawLgo9j_RU;7;(W;)DfP!VR zB>G_Q33y$hE#u^Q!7=9ZPrVGt*t_fjQE<4J1!@(@y{@hbH~DSV+}+D|!v8CiZZsJp zhR93c4F}??dN_@r7mhPYkXMwG^YCE%w}8WOcbUzgtvNC(9H^?8;QCVP`=Av zyQc>S1T@T;&@@o69z9ZzV7BS2{SG_;2wY=zV!85gO6lO2C+r>suVhax2K<{i8m`77 z(In;{CH1GoGJr-q0h|J*(1Ef-y%TYSyDmr=K@8jjz@R_lv33qKHbdTM-#e9EgBr#Nx{{LWErLxo_5{eTN9DWv4j4J+agRl;{^7o&}1_)YD(5ZrqI_fAiWF6pQU+ zu=^>#piBT^OgZ%|5vTRQ9@2IOLf(tA9>h7oPc_ zPA2y6U*NI+eI9rB%r}CszF+@3B~Y|C!DIiQfCE-49C*Ga=sG$BSqOE5oz8$G^E9{r z@z4&W|9I512k)vZe~i^d3Em(3{|$&hU3dco(jQ;`1cc6F5ODwg>w)KUMOYNLDc7^V z4GqKxE+{c1<0Gh~;}@IW41utcZ5-l-g)v}q-}!&f>rbMHFP8T;mg+%%KUmy4_h;Jp zpK@NpqW)uGATs;_>p9h5Pi+MZ{+F%D*-n=b{os!ofk2TMiQk3jd#h05(_O$%iu@AT z#NRm}+?`JO?+pSe$sdDO>=1)9e@cSiT=K^+KrN3Q3Fh*u{g16dd<5A!Fu)tLKR%OS zRJj9oj|@MoS`nU36TG?q2dKPiS^l>2|5}b!J!%$s1D6pf6Q05h*fwyRzoKUp7&=S& z&uqMEClj?ni-PT6JB8m4{OpbXGB|$7e{Y94So7ceSi%m1y>hbhX&nD++kPJ5<1;8q zKINVksXWa#BWrhX3q7fMdF)=>JL^-DUL9)lzkjD?W-h0*iIYBf@SxwkwANi-R<=h& zV`yk7CMM=!i35D`@o7MHfS#C{k+FpTB+y>zMcmU0$5mdu*xpXkwYIj_)Qr`w0(BA| z9v&efEj`5IM%}&BK!QI3?*!^4A_nb~VQLzUIa61#=|(ca$P(eVtbbJ2Hl zVPRo%@@wJv=;$bRyD&8*Bt#{EdddXlki--WG{n>0Ki!L9A> ztWc;@m>wUD>W>Rf%q$?lo(2c8DX0J0e^I@4)3XqY_d;joPCW#)rf}UC73m(~wKf|D7^A&$TQtl4&3?9$$Tg!gAE=B%tUz<$3`s1gq zX2gGdc;*v&Y!A1pZV#QPAjBqHzO-`;rf zGMKeH%nVEzRCEb`*z)Jg{yi=pZv2y*AJgDZ)`LZMB;k2*amZVIJ@wC|!JRkq2v6bG z7x*>Bdv>-E6Q)yCW@q;Lb7#CS2eA`F-s6Y;W50RgQ+s$z!A~cN$0)o#{vP_&cuPj< z|9NXLNpLt%4Fu-HemRr(e<%H@nf?vgVuZK5ySt)d=qlom3%Aq!_)|YHwE7$y%et(W z9UmW$#X7>OxqiGgF)|Wy$38{fyXQIydH{iFQ|$a2dp0wrdHOk&E#xmyC08=p-`|f% zLtdT-69b*GV9oAPz*m_%R4Xeg28V~2#z8wu}@Pn2!2pS!t=0 zo!zHW;yz(pK0ZF!$zk-|TOoda@TvCUCwdn;p_b%?yyyS5f0yDn2wqYEU%}g|X_p`P zhJFaab}`ebW7+{JxZ$;~`stqB24FQ6Zj=r-u2m}P9He0?QTx>8DCdDJb91$g>2&_5 z`1YK-~GyeL1~DGPpHBo$#Qoa}cU4U|RTWfD%UW=Nfi^w_x+B zt^j|-yY`=PfJM0RNPPMia0zg_-+xc-^mueq{%aAh@zm>dgXh2oU)F-ypRVW@Qf>xR zZvXSLzehR+%Xlc{hi&vfPmJL|yw>%7{vUhcS0|%jHobBu@Ra494rP8h?R3jdhr&Db z?%#`&sbQwvDrP#3$^ZH&9*z0+Ag8AN_rki4K1)aaZ3{P;*{NTjS_$@l*$uoc@j2PF zCjsPrL(QK$Q3{P#qg>JtI8){L2&ZXY7xUf(8G-O$DEzykgv3t}5d$t$PyhaH z*jfa;`wxpn-MW2yIy1@JeDK>;_$|px9X+~r-d?TYw?J~QQ*7Aw?&6JLUI}>#{89U} zg;B})qK;;%O74I>oHJjea2#CMxN}SLeSfZo&0=r5d8wv$OIE{o(o^GCFv9`zzUIzQ zOkm~w@KIfx;)P{0`Fb!oG0M91!mi;_QR?5))7*vtUa5a?8wNPVW70`x&i)8FUgsmm z#MESa=PXv-eK=AU2D-b>yl-YIAP>mRwE)DLSt0ssh`vSzL1%gUw1k4XDchF0&f(_4Pg2 zUUpd>6-fS3vw|5ZZwaN-N|g@D%E|(1gX;IMSCPuSzu6*+XC+cKW_y@l$?6*zoD=_6 zQbK(3;>WNsG}&I^JyB87yLTG_4Iq6tIQa6;RkALHe05MT(>nCj(bj%{m4TDUx4hh? zD^a9$BF$&L{z5Z-Mh|wON7C~~UVi?B&xsf44k!BAoh(TQDr-B^AvCkIv(z5ZkEuVJ z;3W9Vm*EmPXcm1$k*hDtCh3j8*;v(ftrw0EKMmT4rs1wekDoqm4J2o4WIGG0#%e3F zq{b$*?U83MTwz~Sv#?lpnC~0_ZK>gs59sXd?4Y%KDUEfMpz(IB+J*0TIOM1|5hE2p zvJFlaRSUSWX1O&-k%XlsyPgE>eN9cxdlFjR3ftsCjR}u61dy7Cen>vJKUU>5^4;u3 z5tP@g_xIk$%qR+CoZmf^=ukcW{4F8X1^j-XP$(vy`PW89O6;!N9#ONb7d*z{stxln)GMB~P zru7*DtfGe;{vv?l!P&}mksr)igUD{&=qoYl^5wYXKi&B8MhGq6BUHFTOOZiKEU$(7 zf?f!RRvB5G9f8B$C~8}4=v715kLbYs*!0-;+hz}AflE--z?Z7mYOC#Lr0-m5OLGLh zM!*e*8T@>GuP}%zyd_|N&u>*W&YPgJ%g|Jp$I0odi=fSQ|$G^Mj>7+R1Z$Y+ttyXQYj6;Papj;e`(+8V zHyw^xL4F})BYQsw$T?-H|e@u6ThLnTki?TzPol zXgr>DXCmQU&T(~^(Za@NZE}*4NCLDV?Ah>%tA~9TN43-^SCy1J4tWb> zJpH)Qoz|sLMhhy!p-pA3*4mw63sC3tWxRZoKb$dF@0{OC;tmFrmq%Efw|M7&E?{W| zI(5;H$?2vbLYN3EnIUaebr8l779ky8YDow~N{0{7iKDoPif5Be!_{&JU@(|3BdOtb zRvIH)xY09eaa8d&Lk?PTbr(Wd17mAcfWF^Kz260}!xxL)?_M)JSDe@OXI1~4rb@V4 zwkjC!^OfQ=Fx11-JK%5RBooei+1JvIv6V(TTU?!#(0|V-mig*(FR{Nw@~$Y`7XU~J z0uIfCslZE^Km(_9~9@dICQd1vKWc_-kCMifAGICG1ZwMMC-vwVFWy!nwq+^v(tZ= z_hdipd9y+GlGU)IYW{=I@qW|Kd{i2eoR|z=2CN}5 z$_78@ImAvxmUgkY#d8`rP815n+y>UwsN0$jBg0oGZk`J`r_`2k{U(L>QtT|Zm4F(L z+9A*CPKAq)C%Wi!>bT3>OA7gNW$n^lpC|-kd>ulm5koG(kRlAa-JvQY+P)1VR_*#&+08AjMd{0>5R^?=FPg~E-P6*QN zOUY}AMIWYL2|wj}EMJz;88{P?kf^-8AN=4wic}vK%r6bd`(4;|J9e8m*k<#=J}>jD~7%F&MzaKQLKeE<7 zS}vsgGOUz5^FYSi+gi_i2*kUswze41I z6Wq_%{pb=mVokakKvIRow-guk#H)pYo#e=HY4)k*${_S}q?}xqy4wmA5#3Sbb$>!y$6lLTI_X z&RytGe6M0;#xW*_Gftv3XPAM{W_%Qc+*u?XaNFapF0sPrsqe7|AR32;h5|l%v^k3e z!4dk1l`K%y>wsOa)^mGl07MudYmkmuSz5loLI)nM%!y>v0HF;Lf2AXMMOMz;3`xxEl2F$uy9xw$o5q07N87lKxnPTZ~@#?rJ_ znrEv&`wa=LFgkC4J;~>Ry+hC{i$-dU{ib0^G*uX{1x36_E`|%+dJQxQdZ7zQMC|Vh zL6t0_54&=Xo)_8AmQzAe!5{6kOP5M9BVEFtSzc=3WZg0`X)C6XicjEp_^jGyq98h2 z7SA&A^Z`n7No#7}C?tU2uD4 z$Z)aOZ#XJl{$z2YE;}F~f{|#Z`RI|CyUc|PBgIbibO?MaqsMM&g+0>)W@elAFD?7o z8ifqf!LBoN9a-<*nSsM`gZY@VtSb?;RX0_Gu17I<$CVw-yc|Y`^c{FM3_NXTu(?GU zY4wi0FZZl2qGBzj)_vpzbBy%Squ&_$&^q(UO~7sV%VEP;hVi|FU=RAjfMQUwS4N!lkgnh&{+d(HyS?Rd{8bU6E3oD@7rm^Spm zcz6fhQnxxWdeZVpjI*G0urxN8k?46K(B^OEI3^)b+k%G!Q~m=KoSS-Sa;gY{`Hlyd z^9B{K{1WW8my^dF+9B_AT;&k`l5l|i)u*pQT=-sB-Y<%iM04rJLZ5I-B{n=(=3${~ zVK3j?33d`q&2odW2fi>-9Pt&R?j z)E-5yjyY^@WyTA`9AzB3;`g^!#}JqiJ}+`N z<$i#@SY!v9vEz75KGyj>;P-gPR&EHzo&YCYp&{Q#bmVnl5JO_L1Eo^ zdwqS+z<|}ycZ)G& zd{8(#>M2fY@34ihj(`qD@Klw@u0L+K50sl^tJtha3UWrxDtIVRJwF!rnQ2TO@3&1s)oS@m z8Sve-Y1?hPj;HsvDdXIQoEjQQwzUSJ&Nr-J`S@Y{#OPP{-MZv>Sp_PEoDzDr``5z6 z64u2UmLC;bEWcWwTv}KBEi}I?eEcP>KxFu+WEJ4|Xl|9uNuEdc5s`1Vl_DRX9`IrM zQsKkc{e=D5U`8SnRQ!g;+&ujxXKlZsas=j1d8W2(n_SzlfN`cFpTF10-pJnI-l$CF zQ1*}qGlqkIj7=P-HuTyqfUUalsiVEoJh@YqW_;{+-ZBiAKO9iUul+4TdX0CO+dW_@ zL(b_%saOBbkKHrr0c3mLlc7CAz1RC1w~gpBbUn8^_yCLTXm1~`urt66m!@lUB9U7_ z9&~U31bv)R&-2!!GMkCx5t}-M!@Q!qivktf-@O3t2OxoAxOwR6TnQuskWqVq^yLV* z3+L3)tPOa5#WF9?TEyLvj}197r~ zt0lze2nukR?_gbOjKH0?+t~;>Iq999xBPtd3-q8>spN2|4``Pxjg-48B!npg9jjW0 zo5+Fq_#6QN4!8YTHFQCw;G~VNS7}C2P)SHf#e9<3@nn4oy$@`N%A&>9Sy0i(-2)d$ z92%+!gM~HD#_`>VjfSn=n5-%n?J*6`#)wDPeM=qI9uD<$dVORLaQ6Ao6`> zb+m`9NK4b=H7ERlBp^`g%CBO8Q(r5|C@+_wu0`29+Ol=i0Uq)BezLCtE57}GWkY>H9vcplv4Y8Oj6C6ao7QE=+$TlV$ z)^u~_fii~?b+@8GzW_f*qFCV&?18?WMDtj1Zgt@*Rf%L(#MzQ7-{VGBe-)Z&%9I{^ zj86!}2%M`{QCG{*es&EW0cB=8`qGQIe{^heR7|&4@>JHXW_M-9Qm9%*uGP3Bb^xUB z05#Lo(?QO;GFW5)Cg$M*`dj#hogT)v1k5ciy3Kde*$HI-_?2?5q_nub6ItT3X%oXp z1aos!S5h2~(=1QCMoCFdId5iDR{<*t_4f8<6>afUw`E$gJesgisyreu&HXfcI zO;Xwg+lJz#@0J%ANgi4C9-FF-))DdX@GP@L`qS7L8Jpv>Q&sO78&eDwaOt(Qpv47; z28G>KB3`+IhaO&-hhE#?SJOkdTWl}!wxc9vp)OZrO+cJU z=F}(<$PuxR zAn1sk(RyvedzhT;mn#{?%9gS-qcoJCGvc>*p?2HroVcqkMjU|G0q%>{P0QHJmc{(9 zHX8N<^n*O!;3iM5geF{%i;K*yO5V(yaohbhb}}^QBWY%>UXUM=AAL{9GwIl4!r@uh zQQvOiaw#VpFS5Sl)}eR>_Guu8CQEh%aUAq}OiuoA^9CCyVc+~^o6Us4y&VdrGjhN#k5*4AF>h9 z%2-fvrL)r+U6}dq-C>SSozF>zL9?Ztg2FQe1rm}mWpgo7UWQT6js;%$No{;&RAgk7 z(|#ecF7$XiB<#|Jm&DOiudV)$kZZJ8j~ugRo*;CDP7VSJ3#k!volQa@D@iMn74ydK z^*uMqqWf|MBs}-|RJ=*N4({_|h8$lsX7s1^gBQsSzAwXJ^oZ_V|F{!GHc7EBqj1g6 zI;uyD1osehSN{%-psQP0c#dqSZ!mhtM<42l6;Rh9+_)` zW+PS!RwZgfOP5PMNOn8rh2U1MOwK9S0Q)1oN#Xfw?ya!XR9g;DUHsy=3O@^84YYXy z9fb@35z=gNT(MB}2$fR)#ak{tsaVo6pqQjoRii+A5tSe3=jRs|*7f1qo%R~`m5BDP0P}(ec|p;^k!)(_`UEiv1L~Y;H1dY2Y9tBJ#WY zmX*elIqDEdzgjUdhRfs=c z{uu|d`h_~s>WULYal02`YDjkR;my#XN{S06T{Z?Fju#l>I@!|&1AW5!5X9X|P z@uBV3s$42w)w}d%_>)lgc8!d<41QAr4>Pfph0%+=ZvRr0uT^JiVIkzW5G{5xnhKwJ z08LKLe}8%33Ac00eFZc#Q>d#4f`_c?K$kk`{NgdL;V1+D{bd{QB>BLzw`df~e6->b_(u@Ws~A4$o~%0w$y85d96GPH0|==x_b88X~Zgckbif(QoT&wO4Q83?nG+Q8=D1Ek)jv+#Ju$T zb5D_N95dd*INVkpaK8%}2E%#Fa-U}Jje$B*+;XaqsJ*QVsfkMY<*{Bj*gW68+D~@O zGli8t18bZ74=s;Px3q{SmP*SsG*yPhwocp%S{#h15}z=~3P0OS|6Rc_6KL%OJlA<^ z*#9O8$c`pTPmTqal@`bGInAxAhV{ONE&I*mm=mS^veI_0eibi#d$;GNET|qZhU@&+BLPax{k;o~s{o8wzldZH%mAQ33yMu$v z)YM&-l}CroGkVr1Q2xEXJ2LJd0cz^8({6Y_e1LBK@uNp3wC0;zNq*!2GYQQK!b{7N z0sQ}sNQoY=iCT-r#cgdJlZR$1j#RHnXpMi*m5o;N+~ISvfAzJjVcnp`x6JYyVX{j{ zYy=JO^^rQS?E!EKIt9FjTk2mQ5<@L(?IaJVm}}N0)^{*h2h9C+j<@-@EqvU1l`=2+ zkK^)`8~MVunl)KB;NcGxVt=xKXlm(td0tuk15?c(t?+nzWONM+&1{lK1uJ?62)S_1 zV0i*d0XYs14hFJ0zgRZu-qG%aKQrYf?I6gfTnr2fHK)Bg{-}sm>#NmZ1wpl%f22%M z5``>;0QKu(TDHftT_2w#^q|38e_G)87@4pF6GKmT>_YYNaWj2rkFvq5s7vah5)^!V zyREGP&Gb_DFHxjvmZi(%s62?ImA{b<_zn=|Y%JjlMGcsZ3JiHu;OFbo6kq6#Ih6L5 zC&=kl=j}+Zc2sB`+{kxIlYg66@3}po(M&Jlc2U6f8#eMc|JM5Jgb>;--dGw=&g0Hb z_q7vhFTk?Ttqm%Bga4_JZD+80Uq>2beCdUTmg3@b?l`W6l!GAh>8*s_%+JCP1qTE;$&2xU$7eRRkYp+r#>m1QO) zqh!}&Io252x6FwevX3=9*XTUYc{@Gt``>x*Kio5)nfspm{{8Oj`@631^}R0M9)9v1 z-jYN}G)_KKPC1ZwQ*bj!yoa5N>m7)=%~XuH3fkI8OweFR$w^9@4>~D!QfF3M6NBDo z6V%dsEDz~7owEFBXNvKOs-SwotB%>{z9kj@Psa6{_ts`8bOeKnyKE?Hp8#?wGcyy? zfrpp0flrlYfL1`~La8VWW@L`s5F8L7ZB_iX_YHhsF8G4gZ`RczWx~uHLYe{^K}TZY z_eS}lu3u6`Wuu0OO-!bFw|Pf>xLgF1h=yq*g(5)_t9jy<2Na52jMHezW3GqJq!)wBDOeb zlyCl)=gg*kf5Dd4jqtX7E5^1q9j^3ez9+kWXI4I8`-!vF)@hV+PxkHuPCLC+>6y`d z>u)U0#`jd*@*S4X@jrJb;6oQ{X;*T=ulJK%81gRM3TJ0F>5!<=w&05%sq0wK-}H(1 z)d*=?@X|4X`g4*pNP;StKIb}fSfOhRxY!sgDk>(9XabIVR#Celn*q{IxU8F^&GiGW zges-=heIBoAQ8HFv8Vugs~`fC9my_BkEFey!JFk+>Ae>9kEA7F=!6e87SDM@x)1}E zBt!lqj{3B5JDKE2o|tP8+5#r;X(7<%!d{od`&PVE1kBUm1W9I)`-L5JXoFobZV2tsu<=M}6z$cHtZGj{ipv`aLo?cgxeo5VCXdgK4viK3+BhCsd|fFcL3m!0_A6!4WqBJp?H%`7_x1@%)n&7)Rz%!_D~ zKN@z@)O2h14Trf!^2#2z;;Xb9D{?!Yv;nB`ROY~|Lwhd#L>mCRz!u?*)Kn+mL$Om! zV>;&BSCX1bB$Akm(_}F(%2V~s13xy||NE1PcC9U2X*&^!Pn;r=ufn%p6^(|O$D3H5 z;?{pw4y~sy^Rh>iA#x9;9cy#WFnoSK@thnZmyt7XjXifLyMB+v%= z&mD*eq)AmWiBJgT`NFNwzS3pM?_M(ks|TrntjbZpsowRO8c+OGdett3rBZh@eXW8- zQ`LQ4sHExup}%`;x}x_BvMnRx0B0K(I`l37Eb6?Rcpf3vOmEq0>3~2qPf&wMot+@3 z!{Klsa!aT`%4(SqJ#PA2nfqdg?*?SrZAv|ifBiK-FON@1NEtJ^u&U%aj4$xlLL2Zu zdj4E-|Ni|F5)xWkH8`Ah9RI0ac{w>d zpS^s1y~U13iwf}%v)MpwIOd}oh2-MmVvlyPw--%SqetM6!FW2J<`xrRC!j0LnZ4GR zzU4#y!+e{zD4UaSDxBsR(U)I}ox-V=$PkvgFK6 z4>vfv``*e|Y7Zt&;YRaE%FK+ig)kp~SJC1?!*PBF1SieDQrpRMY#LN2tMkL!`O23@Z3&G>HV?v`OEm`MZW1dH$P_A8LTzJ?ssp0b}DT)d=(Fgc`c-;_RJ&Y) zSwTVhkcUWQ138~Sm>@tcnp9jt0hLM>Of+Er;8#(0+9qlPnrb1eo`KpD&=C|}wB7$J zNMiBdprnZJKL}mRQdc5{82k&ewbjMrI{W+6L2;0hk^-dm`}d9|ljULafBX*a zOF@B&sj2MB%})+8N^SPrmj`~Domg7)`;if?1=+)malw^|Iw@WV;Ru>m%kW1-QOvrc zA}};Gw5-LBI8YRgmq8%RpQoq)j6xY18m_Ic(-cL3xeNLG4Q{*~ng*qXs|1cdJAMaZ zXMEHdnAjv9S2l#}5oKkmxX!^rH(wD1C)Y3hcuqXjE$)oLD41BK@*h| zc5ngGmra*znXv2UiG6q(x&Z9TG_PI64|Z|l08~cY4ZW6MP*7aNH>v}r1$J~l+Qq!c zPHgWx-;Jq0B8aUW92|m|rl3q-)S2&q9J@y?{dabuutWITS=3VkVL3oum$`JHm7g&- zflMnTEe2gE>@L)8XXyV4*Fc;8Gv1Y`AJr0<#Jl0M^cxa)eNMApO2cQ6-x z$_um91Ft~g9jt^rJUnDFxxzE zc0@c*K~Ap7u{m{BqoKaOm`H?@`vi|4ZCNI562xr5%hM2>E=&8F=+OxMvM1Y-D*_amYl}cR`AJ9!?!m4v)V0AojU(wnM%F8 z_w(n^^-B<7w=QL73KD6j_7U3gCl(PZy8nF}Dgrm4SfDO*pO8@Lz!wg!ud}cg&#z4q zMtnfB;R#s)< zTbpo3ph`gw16BQE)yUc=0}#7>Z2*nhpvSU3SC$ZTvVu2)fqx`}8d76<(A$6CQ<#rO zk1lMiQH_m_!3#|8tA^6B-hQ+M$A>d3$SX^Kf&sJ(ukLH*Z0F zH$T?LaxViSM%nxceGJbxhZMJsrr7o3QNtbMp%JL7rh#Di!cyHduY5aPh^ZPMchWxv zZpBj>1{^Pwi1|)10{{mI7_fXKUkyGs7LgFmtS6Vs3vJN5&3Vy1ipC48A-XYka*exV zwviGMbI6#~mZc>d8KWl}Ruc}&M9__vl#Am0q_ijz?Kow1<77203F@=7Xw;iM0g<1uL7o5Myz$ z${-!e3wgP@S2n^bhK9Skd}c>=P>y4Wxtt#zha1{7gha&1qfkR0rO4OhxvribuKh^o zf`aazo?vxBk;s8BmsOSr?#KgqF1J{jl&I(-u##9LtOs-D=`Nt*%OHM`yIP-BhZ`J!I zxx~Uk8O~Teeq(0&qerb!sN3o36dzU43=-d_`=Yf1=l_6~re{u{mXwsNZ)j*8dHj9U zFuA$3D+vpZ09KE@yiPOsjt(y{Zbpp~zOSH|vpaBvN+3^P>ReUL3)X5$IM?gui%4V@W zA=86p+QRR^Wd_iMn*~MkLOx_of1;1*=;(O;`ZZAggCjTSIFmrx?cfWIZr{ddi$65G z2w{P4jG6dZTiZbr>2Pj4sDu6dmY@I#Id<1M69y#s<82F|>45hQ-|Ty|zP+=JF<8Tw7afNq}6mLq$o6543`Vs0%dKtMFLF z7l}uTOG;W3omx9`3_uuAp*$Sm&}Oz*+2e=-B=gE9F9L`c$o6<;jlwRQ`4h#fCg=tu+@(cM=7g;7uMSwFy3+(1UUpNqEnlhqoX5CI;@|t z!3%iXVL%)C7JmW`XJh~BN1qVADa(OZfF(yeyYGk4iH6sW$@>%4=Nk*r6`8@)Wqlj& zN&{S`>d!n!s#lNg(+X3Ul9H0$-qh48o;{Oay9kwDi5g3m5P^AkOtZ>X7QMad>f#a? z7iVZ_IOP`%(0=z0-5`&YC-{tx{MQYy$Hf8Yo=C#R3l^6H2uK5}FbRdo$;r(E|7(M0 z#eRfZe}uVgMr$fKAiw{Tl}FiO>ysamXi=Z(TULhM?f8Ah&MQGRq&Hq98-})#O>I>03fyFf8g)%Ni!5;E`3tT!bCf(2)LvpGZ@Giz&iO<#xUqR^bO{TO$fdM(J%Q=M^*Hd zdw)sn{dk6YD8a%y?)iFE%f6Wwz0uDiXo#1ZUs#yA@othTvvNCpkc-fx7ECZlq3V`R zd1AI#5Ezmm9i51g8CXMM`C{S_40*5|h!*ofYeAcABco=J>||;L%bcrhJf}}j9%V#W z9!H@{2M$Hf2B<^0rdN2!4E4OadYC-NEHdb!OuNGG98~I-m*34_@{)XXX=wbbzKLF; IuHDst0YOHC z!N@qtiEk8}0y^6rg~;VbbMFc>Q0i6}|$7V3uc_?52j_j`>T638jj2;OQ5(!WDOpe~Gb zb$O>Krvg6YFl{SZA?FOcTaJ_nhG?O>(EAoJx{Z7_w<_#BN+?rykSx^ub#|$GA)}Xc z&S=LlKrTb@Tf4L&F30I29V1qi4P%;MVZsk_&7?&q{XDTLtP)`q1pt&N(Qwpi z>S(JI9zqu2sP0G14aq0M)aIsXipj8@xns<%8Tc_L*Sm9vbw`GE$A)!>lT}O^XAtwc zOP5lDV3d31Y>T@4Njylz5<54n9-~-e&gq5zuOUfZGJw4K=We@p=LQV>=QnQ2qD5to zeZE;eOPa1+{UAwwhZF1))YN+%@tesXZX;iPJ6ZHTKHhUR zg=JQ@X;In~X8NUBuiCwIV)CX6tTPt`9uOH{G(&v1#Ai2;h@f!gQ5Mxxgxd@$bCAW6`mla-s*m;t;b6nh zh4=X7F)8bB)lIX^Y@UUmbCW_E7}qd8u2EFX}hw9AtndW zFBm1NlJG+s)I>bWAN`2P4sq|zn0pGw>I^Teu^39xPd^6

fYoYZdS z0JWPj)^20%_PfNCn(Q6eS#( z%0IsBKBWKr0CTEYmUDVdey#u3t=A*<}Q+HyVCDEmv{dH?F)F*`!N6j2JR5! diff --git a/ext/picotcp/docs/wiki_images/port_to_os.png b/ext/picotcp/docs/wiki_images/port_to_os.png deleted file mode 100644 index 989f723da3ee424d0e3b9d4145ef626977a72141..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7080 zcmd^EXHZjJw?=&tP^2m<2#6FBr1ui=0|e>PYl!qt=#fwY3L?^!4gyi6NPy5gAxf3r z4WSpMhYkTk$c^87f83cnb7$UvckZ3D&zw1D&RKh}XYchqYwZ*BTuC|%XK0Wv;uveA3a`I(&O)_ zRn;3lQgtB`efsxMC17AdJ`}(S;6Nh%ayCN-Pd8@eiq1H=$i0WZ$}_m=`LQcFB~P(X zRxr{)!_|8;;4Z~;MTT^W`%w*lQ9SD4rFh0AeCf$G9~uh7x7rl%Rje0y2Bh?}*WdU+hUQ(Z?^7VfHFcVc4PE^q^U9@s_(Z&GMbilsj?SMXpXt*fKhKTsrMzPk~pZw9kj?QxiI zWw2k?vhSYC%DA&N&zXmUVAIMpy zi!Yj-E{};1MIiG+SCG;+Ezbh{u2)s;O3J{uS6B|0o+9KIqB+A#tRQv1H6oyd-o08C zu_xAP-oeM#G<1OpiEssfmyb3m)4wQzQ)rmKM=1oZG@zb1S4elAt~G42?U#1?OgRW9 z3h}BKU0=m-j(o9=rf;5UkrU$O9T@W~AKh7IzQ=mDFv^QRSbexXjTb=sAFT%D>YNi3 z6WQGbBkxFbIbo}qr(&yw6rwM5R)&=Q&rb&0qk&$tSsWa>pZw`qYkqci@+pS=oNbmU zD~)R<2G*YtegU}KMK>LI(Sf(EODy0Wmar2_2_N=oI@kcDrxUo^VAx}f+iti$12 zSyS&5pS}I2!oNVhsaGw)rUD{g)t6cB%1yVmJ*WPVlH&1VSJ!yl!|xy+o|UDit7Z9# zw%ONFYpifZ<*lGu9^uI97K^kl^+p%39y+LviI>3QlRdO(c|?%B15))P3?pVtjV0 zB8QJ|==W%GMYe`faz*Y>l!TmZS-g`k4GU#182J>Tsiu}U+8Qj=>SNCt5C@Bc;vLQe7x3wovit*xPc{C|*dYiF+Z!k?cKwzr#wZQ@=Y@@rBX z)OiS-z4-7Uu@DdFil)%PV4or|IlKKGCf&EfzO5 zQEXM8HD!cu?IG-7&Q4cjXDc&IIN2i(fEKH=(zErDGfC|5^Pz8_+Gd** z)#J}B*gf3b7?_xn1CqE@OS|K*)6(lx)9c@n5%&JU;12w#>Z4(u#!!A5oSvf~Q&VR% zoY#4N^@fh3V$-7>B$AzQ?CAwYcMT7RPFCDdjc)DFDK=`JC~+Rm>kM(AKUv>fjE@zT!rF-6`gU;RGK+xS(eEOgSg6h2((&XS)d<74u|B^dG=a(K@ld{)4>6f(eCj+| zKV=5SPh~eMo6=lE$4cFQSCHXCDDxTW>s7N$`;Ps%a-II(F5nZ$WIhZTnvB$qWFUV! zb@Z#Q`}+n7=SVUT(QaeAO*1@Qkjx;Z6UxnK?b>{Y^=!XX`bA6?EB584Q{488R78 zJU`XGt{nxxuw!6mO+NU02H4cS-nMe&}z9Yp3NCnu362%sL#p4o>GGx=uyjn?3L88Yb3kmc`N^myDd&wUJ9Q~PFu0O>iUdPjnY#?YA$Iw6ELKsCv%Bif-CX_4U3uLvm0_S=r-oz zi{UnlGGp+G$;;;}J%%qTx18=0=H?+6O$QV^m&lf58t(bLT({*Fo-iR#^J~Rdmy7;F z>=+nkF{Yo2Nj!;L7vMXDp01zdKH$>qzjl)?CyHTdQi}1nNZer*LtfM8lkVsxPEHn! zV*b`^yNl1TgJ{^rMFJ?$_$QOfxU11>>=DR;)!xDO*TSag&X=I526!hGUie^n!BK2x z1qM~BXQUEAdrV6)f{-lesCUji;8w{Le##^7e2=ILRzxe&g-%k1Te2}h;FfH2f8r!M z(xjHOURf$&M}lJKmIPR~8HL?DkN9mZOeSIX3y)wyRTjo4i%-M~6iuH|+bUziCMrw- zGr=w*fa=q@G4+RI&_WezTr_w5lw$AXsJTVxk#k9~-g+kPmp&&zsz$WGF}!1~BWEm7 z`mAAOb4Q!ziSK*pVQ|KG&7>4T?+;4=KNtwnx zsd+C2TcWvXxM&fqF7$(Hrz}>D(BJBT@im;%W`7_ZDQKL0snYNNa-w=sO&o~uhW*hu<+RtS9Y4bPI^)4 z0Dr5;FhXP3qg46W{N)Al#-vxmB-FBl=Us}V58-o0)zeAuN3TO3eT(LHoM=aNSKjJQ z5LV72hv?aZqq(SHcXkZR(%?;4HgH9Q`?}8$)dn!*SUn9_q%OD5uxbkdkAFFIX^8;p zSd&_^sHzZUL0QJ=+P|wXziCf-;+}X|@Dr``=N~ku{cLPBeaB|6A>kys|44bCz`R zLX>!N&@=s``m+_7qO2Rr)&fYS0F&huTx*y+RS<%om+o-9a3p{lWiLo`m2TKiPPKtZ zi`<>N*SyOmbWQH>q?#Cu^b#vJg=eRog}Odh{{F^i3P;VmjD~xCWC>DENF0;80={)@ z$|bDb9CvsK3Y(K{vpfrv zmEJaxR{B(J7}KM8_Xo=;L5aQ|82=Nh_)uUDhw?kKGj>+1Z5#ZK2yTkj!;UxdnXaaV z+;n>-(5Q$`2!gaJjPqHaQ&N0v?8-S?Y2rH5?4v7Z@*!J}8xTtHRbCaw-J6!)!`~q- zSs2y@*vJM>etKs+WD7DDLqhjX7;#S(OoiA+76ILXx@JMTy1JSM@+8FoyQEP3ccIPr z?V00+I(WzYs#mY3QC;eqfUJ;EK;I}ODBx`2pe`O#M*J7XSc{uiE+{^+C|OsKJS5D? z%R-)qC0FP?u%bJ;H)0b zhlwZ**T)89T^bDQDj|4^F06BM}H0gDb zk&%&%2=KjU4gqF~IjAOE<4|SCgKf%DYl+EdVcK)Y9%MUXefwpz$0qVfvxc@(}eJHkVIFeG!!GxpOJ?Mm$eR z?^zNT>}?+=FPq90_BEDeM{&Fb7<~;2Ju{(=j)&)kE=k)V%xYPkv|13z@Aj+uNlVwzA-<9JVf3uRbtE?&01nK%a9mx%MK1 z0BIK{*%Dk~WX3ALkP!xkFofv?5jRZ-`a>eSw?Gg|{v5}?)OZ*}@}1l6ZnjcRgAafj z>dj0*N=~}-pkIe_E47=Z(voLO(-v}^8}`jtaui#1`h`-i1cX37HLaCo9=MrLAj~z< z<;e$SC9oC6M1g69C3bRsoh^H^*@&7k0Ds)MtO32j$>pn-eYc8R>{k|59&5_F~Ft-SJZVaiOR$v*lsfy z)XWkwURHGuoA_7(w!4WL8;-M;eszDN)7`07+?-uS{b*l5&3D z_$#sr;d=+*wcIAh4n3Z&^8X%gU@y2~!X(F`g9A(yZgx4ECUPi=mRbr$)0AzXjhb!0 zj8Pp2u1(;_F97kDwZ&c*My&!p>9mbYTU8a0a~C`?u=lXtVo$T}a%Hxp+_XaBQ5Q+K z>5l#fD?7|hYXnHjo7~n2i!%9#cpTzW5vB|24z--Zz9tN~VSg z|FEE0yM#%`{!-@$cB|U%$Jdntc-B@^Zi}Q`aLKIF6c@EB#tVj&t(zN)066x&clLOAz$(5E0Plw!%(7RT3e%9u{(3 zWjsq|WcEE>uea;>cTZ&$#zyd{>SIOy@>c+x={2rn5Az9dq+c$g_n22zi6K4ecaULH z*l&Sbg6qn0v>+wVB&2N}imEh6fm?}BUWpG%=DDf)sk*VLAPI%z00x!G<4TZ}Gs1V- zFl>cG^$-?C|?eW_4#)Z@ZlY$b2=@)+`rJbl={-rVyO?CZ+zQ9&#N=E>Y_n^8ZbTTWaNxk$q)z1SenjkE+tL!s1=o^! zeYO>0iBea7xH^V*@Y{S&y(kKuvE&@u3zbh50=2@EtD$}9)c9E^^r<)@!^As$rmJ`Zi6pK_m%YyeJcMo6 zM~~Q*a67vbnBH)Dd3?ss#-XTqi__~jUf0oP@;Ht7qdTLk>&xBPi`-AhR|Ew)^fRq2 zrJ0MThNIuami=Z(et03=P{Y9 z^y_Tt{OS#NsBG>|);QfLu}p3yK!$SnN;!%^GmaFi<8J=qv$jRGZCY%27fRo z2MeMmaeERWN!I(7Q55RDpNz?LIzbNNx;j}GgYG`LJ(M)JF!$xJ2f_yCED3BAev`^( z7f{>I#p(&S3{u0S2GIX#rZ~t7??oTOpz>F#Icw1BN)j+S^vW?vHc;*EaBtUkZ=(^p zhF<$>Vl$Qt2z?OQ0NwU?pVr%#AUP9z`<(R$Eztv{h4u0A@d54IE#FZZG-}pMwX%|R z{fD20En5zr9|W=stgWw`iQSV9>m^IW_*3pes7Z-!VND|Ln)m)L!pX_Y&TCO}KzrSI zd4F>I+x{)Vi#kX;!%{CfKk(T4#M|^Wn^J_Yb|@$0dtVjm`Y0Z?$ixt!iqXrIwJhFp{Wv$Z3sc(;MtDM@8Uv z+)2h7xk)MIy1~d;yRQyxO=A8A~*!Dm%P<1SkHHh3@nqqy(jdD zS!MEYBYk)GbCa>}3YkVuJ{>$HFGF~(>&a|>WgQB4-3{|xes95=;s@n_t^fb=uPAaD dh0AP_F2zw%PVlKbw*M1XnosrAkSZ@;{Rea^jw}EG diff --git a/ext/picotcp/include/arch/pico_arm9.h b/ext/picotcp/include/arch/pico_arm9.h deleted file mode 100644 index ca4a35c..0000000 --- a/ext/picotcp/include/arch/pico_arm9.h +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_atsamd21j18.h b/ext/picotcp/include/arch/pico_atsamd21j18.h deleted file mode 100644 index 27d272a..0000000 --- a/ext/picotcp/include/arch/pico_atsamd21j18.h +++ /dev/null @@ -1,61 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - *********************************************************************/ - -/*** MACHINE CONFIGURATION ***/ -/* Temporary (POSIX) stuff. */ -#include -#include - -/* Temporary debugging stuff. */ -#include -#include "halUart.h" -#include - -static void print_uart(char *str) -{ - int i, len; - len = (int)strlen(str); - for (i = 0; i < len; i++) { - HAL_UartWriteByte(str[i]); - if (HAL_UartTxFull()) - HAL_UartFlush(); - } -} - -static inline void sam_dbg(const char *format, ...) -{ - char msg[128] = { 0 }; - va_list args; - va_start(args, format); - vsnprintf(msg, 256, format, args); - va_end(args); - print_uart(msg); -} - -//#define dbg sam_dbg -#define dbg(...) do { } while(0) - -extern volatile uint32_t sam_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 = sam_tick; - return tick / 1000; -} - -static inline unsigned long PICO_TIME_MS(void) -{ - return sam_tick; -} - -static inline void PICO_IDLE(void) -{ - unsigned long tick_now = sam_tick; - while(tick_now == sam_tick) ; -} - diff --git a/ext/picotcp/include/arch/pico_avr.h b/ext/picotcp/include/arch/pico_avr.h deleted file mode 100644 index bd5f720..0000000 --- a/ext/picotcp/include/arch/pico_avr.h +++ /dev/null @@ -1,39 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 de3f475..0000000 --- a/ext/picotcp/include/arch/pico_cortex_m.h +++ /dev/null @@ -1,12 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_dos.h b/ext/picotcp/include/arch/pico_dos.h deleted file mode 100644 index 4c12a0a..0000000 --- a/ext/picotcp/include/arch/pico_dos.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This is a picoTCP arch file for the DOS 16 bit target using OpenWatcom v1.9 - * Copyright (C) 2015 Mateusz Viste - * - * This code is donated to the picoTCP project, and shares the same licensing, - * that is GNU GPLv2. - * - * See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - */ - -#include /* provides int86() along with the union REGS type */ - -#ifndef PICO_SUPPORT_DOS_WATCOM -#define PICO_SUPPORT_DOS_WATCOM - -#define dbg(...) - -#define pico_zalloc(x) calloc(x, 1) -#define pico_free(x) free(x) - -static inline unsigned long PICO_TIME_MS(void) -{ - union REGS regs; - unsigned long ticks; - regs.h.ah = 0; /* get system time (IBM BIOS call) - INT 1A,0 */ - int86(0x1A, ®s, ®s); - ticks = regs.x.cx; /* number of ticks since midnight (high word) */ - ticks <<= 16; - ticks |= regs.x.dx; /* number of ticks since midnight (low word) */ - return (ticks * 55); /* a tick is 55ms because the i8253 PIT runs at 18.2 Hz */ -} - -static inline unsigned long PICO_TIME(void) -{ - return (PICO_TIME_MS() / 1000); -} - -static inline void PICO_IDLE(void) -{ - union REGS regs; - int86(0x28, ®s, ®s); /* DOS 2+ IDLE INTERRUPT */ -} - -#endif /* PICO_SUPPORT_DOS_WATCOM */ diff --git a/ext/picotcp/include/arch/pico_esp8266.h b/ext/picotcp/include/arch/pico_esp8266.h deleted file mode 100644 index fecac73..0000000 --- a/ext/picotcp/include/arch/pico_esp8266.h +++ /dev/null @@ -1,58 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 79ef41d..0000000 --- a/ext/picotcp/include/arch/pico_generic_gcc.h +++ /dev/null @@ -1,117 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_GCC -#define _INCLUDE_PICO_GCC - -#include -#include -#include -#include "pico_constants.h" - -/* #define TIME_PRESCALE */ - -/* 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; -} - -/* time prescaler */ -#ifdef TIME_PRESCALE -extern int32_t prescale_time; -#endif - -static inline pico_time PICO_TIME_MS() -{ - #ifdef TIME_PRESCALE - return pico_ms_tick << prescale_time; - #else - return pico_ms_tick; - #endif -} - -static inline pico_time PICO_TIME() -{ - #ifdef TIME_PRESCALE - return (pico_ms_tick / 1000) << prescale_time; - #else - return (pico_ms_tick / 1000); - #endif -} - -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 cb140c7..0000000 --- a/ext/picotcp/include/arch/pico_mbed.h +++ /dev/null @@ -1,185 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 c2fc7bd..0000000 --- a/ext/picotcp/include/arch/pico_msp430.h +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 b4a3599..0000000 --- a/ext/picotcp/include/arch/pico_none.h +++ /dev/null @@ -1,22 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 eb3f117..0000000 --- a/ext/picotcp/include/arch/pico_pic24.h +++ /dev/null @@ -1,100 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_pic32.h b/ext/picotcp/include/arch/pico_pic32.h deleted file mode 100644 index ff902e4..0000000 --- a/ext/picotcp/include/arch/pico_pic32.h +++ /dev/null @@ -1,54 +0,0 @@ - -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_PIC32 -#define _INCLUDE_PICO_PIC32 - -#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; - -#ifdef PIC32_NO_PRINTF -#define dbg(...) do {} while(0) -#else -#define dbg printf -#endif - -/* 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; -} - -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 /* PICO_PIC32 */ - diff --git a/ext/picotcp/include/arch/pico_posix.h b/ext/picotcp/include/arch/pico_posix.h deleted file mode 100644 index 427fed8..0000000 --- a/ext/picotcp/include/arch/pico_posix.h +++ /dev/null @@ -1,137 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 uint32_t pico_ms_tick; - -static inline uint32_t PICO_TIME(void) -{ - #ifdef TIME_PRESCALE - return (pico_ms_tick / 1000) << prescale_time; - #else - return (pico_ms_tick / 1000); - #endif -} - -static inline uint32_t PICO_TIME_MS(void) -{ - #ifdef TIME_PRESCALE - return pico_ms_tick << prescale_time; - #else - return pico_ms_tick; - #endif -} - -#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 7e42fa4..0000000 --- a/ext/picotcp/include/heap.h +++ /dev/null @@ -1,107 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#define MAX_BLOCK_SIZE 1600 -#define MAX_BLOCK_COUNT 16 - -#define DECLARE_HEAP(type, orderby) \ - struct heap_ ## type { \ - uint32_t size; \ - uint32_t n; \ - type *top[MAX_BLOCK_COUNT]; \ - }; \ - typedef struct heap_ ## type heap_ ## type; \ - static inline type* heap_get_element(struct heap_ ## type *heap, uint32_t idx) \ - { \ - uint32_t elements_per_block = MAX_BLOCK_SIZE/sizeof(type); \ - return &heap->top[idx/elements_per_block][idx%elements_per_block];\ - } \ - static inline int8_t heap_increase_size(struct heap_ ## type *heap) \ - {\ - type *newTop; \ - uint32_t elements_per_block = MAX_BLOCK_SIZE/sizeof(type); \ - uint32_t elements = (heap->n + 1)%elements_per_block;\ - elements = elements?elements:elements_per_block;\ - if (heap->n+1 > elements_per_block * MAX_BLOCK_COUNT){\ - return -1;\ - }\ - newTop = PICO_ZALLOC(elements*sizeof(type)); \ - if(!newTop) { \ - return -1; \ - } \ - if (heap->top[heap->n/elements_per_block]) { \ - memcpy(newTop, heap->top[heap->n/elements_per_block], (elements - 1) * sizeof(type)); \ - PICO_FREE(heap->top[heap->n/elements_per_block]); \ - } \ - heap->top[heap->n/elements_per_block] = newTop; \ - heap->size++; \ - return 0; \ - }\ - static inline int heap_insert(struct heap_ ## type *heap, type * el) \ - { \ - type *half; \ - uint32_t i; \ - if (++heap->n >= heap->size) { \ - if (heap_increase_size(heap)){ \ - heap->n--; \ - return -1; \ - } \ - } \ - if (heap->n == 1) { \ - memcpy(heap_get_element(heap, 1), el, sizeof(type)); \ - return 0; \ - } \ - i = heap->n; \ - half = heap_get_element(heap, i/2); \ - while ( (i > 1) && (half->orderby > el->orderby) ) { \ - memcpy(heap_get_element(heap, i), heap_get_element(heap, i / 2), sizeof(type)); \ - i /= 2; \ - half = heap_get_element(heap, i/2); \ - } \ - memcpy(heap_get_element(heap, i), el, sizeof(type)); \ - return 0; \ - } \ - static inline int heap_peek(struct heap_ ## type *heap, type * first) \ - { \ - type *last; \ - type *left_child; \ - type *right_child; \ - uint32_t i, child; \ - if(heap->n == 0) { \ - return -1; \ - } \ - memcpy(first, heap_get_element(heap, 1), sizeof(type)); \ - last = heap_get_element(heap, heap->n--); \ - for(i = 1; (i * 2u) <= heap->n; i = child) { \ - child = 2u * i; \ - right_child = heap_get_element(heap, child+1); \ - left_child = heap_get_element(heap, child); \ - if ((child != heap->n) && \ - (right_child->orderby \ - < left_child->orderby)) \ - child++; \ - left_child = heap_get_element(heap, child); \ - if (last->orderby > \ - left_child->orderby) \ - memcpy(heap_get_element(heap,i), heap_get_element(heap,child), \ - sizeof(type)); \ - else \ - break; \ - } \ - memcpy(heap_get_element(heap, i), last, sizeof(type)); \ - return 0; \ - } \ - static inline type *heap_first(heap_ ## type * heap) \ - { \ - if (heap->n == 0) \ - return NULL; \ - return heap_get_element(heap, 1); \ - } \ - static inline heap_ ## type *heap_init(void) \ - { \ - heap_ ## type * p = (heap_ ## type *)PICO_ZALLOC(sizeof(heap_ ## type)); \ - return p; \ - } \ - diff --git a/ext/picotcp/include/pico_addressing.h b/ext/picotcp/include/pico_addressing.h deleted file mode 100644 index 9264fe2..0000000 --- a/ext/picotcp/include/pico_addressing.h +++ /dev/null @@ -1,127 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_ADDRESSING -#define INCLUDE_PICO_ADDRESSING - -#include "pico_config.h" -#include "pico_constants.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; -}; - -/****************************************************************************** - * Ethernet Address Definitions - ******************************************************************************/ - -PACKED_STRUCT_DEF pico_eth -{ - uint8_t addr[6]; - uint8_t padding[2]; -}; - -extern const uint8_t PICO_ETHADDR_ALL[]; - -/****************************************************************************** - * Generic 6LoWPAN Address Definitions - ******************************************************************************/ - -/* 6lowpan supports 16-bit short addresses */ -PACKED_STRUCT_DEF pico_6lowpan_short -{ - uint16_t addr; -}; - -/* And also EUI-64 addresses */ -PACKED_STRUCT_DEF pico_6lowpan_ext -{ - uint8_t addr[8]; -}; - -/* Address memory as either a short 16-bit address or a 64-bit address */ -union pico_6lowpan_u -{ - uint8_t data[8]; - struct pico_6lowpan_short _short; - struct pico_6lowpan_ext _ext; -}; - -/* Info data structure to pass to pico_device_init by the device driver */ -struct pico_6lowpan_info -{ - struct pico_6lowpan_short addr_short; - struct pico_6lowpan_ext addr_ext; - struct pico_6lowpan_short pan_id; -}; - -/* Different addressing modes for IEEE802.15.4 addresses */ -#define AM_6LOWPAN_NONE (0u) -#define AM_6LOWPAN_RES (1u) -#define AM_6LOWPAN_SHORT (2u) -#define AM_6LOWPAN_EXT (3u) -#define SIZE_6LOWPAN_SHORT (2u) -#define SIZE_6LOWPAN_EXT (8u) -#define SIZE_6LOWPAN(m) (((m) == 2) ? (2) : (((m) == 3) ? (8) : (0))) - -/****************************************************************************** - * Generic 6LoWPAN Address Definitions - ******************************************************************************/ - -/* Storage data structure for IEEE802.15.4 addresses */ -struct pico_802154 -{ - union pico_6lowpan_u addr; - uint8_t mode; -}; - -/****************************************************************************** - * Link Layer addresses - ******************************************************************************/ - -#define IID_16(iid) (0 == (iid)[2] && 0xff == (iid)[3] && 0xfe == (iid)[4] && 0 == (iid)[5]) - -enum pico_ll_mode -{ - LL_MODE_ETHERNET = 0, -#ifdef PICO_SUPPORT_802154 - LL_MODE_IEEE802154, -#endif -}; - -union pico_ll_addr -{ - struct pico_eth eth; - struct pico_802154 pan; -}; - -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 31c875c..0000000 --- a/ext/picotcp/include/pico_config.h +++ /dev/null @@ -1,243 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#include "pico_defines.h" -#ifndef INCLUDE_PICO_CONFIG -#define INCLUDE_PICO_CONFIG -#ifndef __KERNEL__ -#include -#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 PACKED __packed -# 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 PACKED __attribute__((packed)) -# 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 CORTEX_M0 -# include "arch/pico_cortex_m.h" -#elif defined DOS_WATCOM -# include "arch/pico_dos.h" -#elif defined PIC24 -# include "arch/pico_pic24.h" -#elif defined PIC32 -# include "arch/pico_pic32.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 ATSAMD21J18 -# include "arch/pico_atsamd21j18.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 87e68ce..0000000 --- a/ext/picotcp/include/pico_constants.h +++ /dev/null @@ -1,58 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 -#define PICO_SIZE_IEEE802154_EXT (8u) -#define PICO_SIZE_IEEE802154_SHORT (2u) - -/** 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) - -#define PICO_IEEE802154_BCAST (0xffffu) - -/* 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 67c5bab..0000000 --- a/ext/picotcp/include/pico_device.h +++ /dev/null @@ -1,56 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 { - void *tap; - char name[MAX_DEVICE_NAME]; - uint32_t hash; - uint32_t overhead; - uint32_t mtu; - struct pico_ethdev *eth; /* Null if non-ethernet */ - enum pico_ll_mode mode; - 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, const 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 99dccb3..0000000 --- a/ext/picotcp/include/pico_eth.h +++ /dev/null @@ -1,21 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 125785a..0000000 --- a/ext/picotcp/include/pico_frame.h +++ /dev/null @@ -1,131 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 PICO_FRAME_FLAG_LL_SEC (0x40) -#define PICO_FRAME_FLAG_SLP_FRAG (0x20) -#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 - -#if defined(PICO_SUPPORT_6LOWPAN) - uint32_t hash; - union pico_ll_addr src; - union pico_ll_addr dst; -#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); -int pico_frame_grow_head(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 067f5e1..0000000 --- a/ext/picotcp/include/pico_md5.h +++ /dev/null @@ -1,17 +0,0 @@ -/********************************************************************* - * PicoTCP. Copyright (c) 2015-2017 Altran Intelligent Systems. Some rights reserved. - * See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 99286e8..0000000 --- a/ext/picotcp/include/pico_module_eth.h +++ /dev/null @@ -1,33 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 77fac16..0000000 --- a/ext/picotcp/include/pico_protocol.h +++ /dev/null @@ -1,95 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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, struct pico_device *dev, 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 5b5700e..0000000 --- a/ext/picotcp/include/pico_queue.h +++ /dev/null @@ -1,166 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 514fcca..0000000 --- a/ext/picotcp/include/pico_socket.h +++ /dev/null @@ -1,271 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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; -}; - -#ifdef __cplusplus -extern "C" { -#endif - -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); - -#ifdef __cplusplus -} -#endif - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, struct pico_device *dev, uint16_t len); -struct pico_device *get_sock_dev(struct pico_socket *s); - - -#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 405f39e..0000000 --- a/ext/picotcp/include/pico_stack.h +++ /dev/null @@ -1,111 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_STACK -#define INCLUDE_PICO_STACK -#include "pico_config.h" -#include "pico_frame.h" -#include "pico_constants.h" - -#define PICO_MAX_TIMERS 64 - -#define PICO_ETH_MRU (1514u) -#define PICO_IP_MRU (1500u) - -/******************************************************************************* - * TRANSPORT LAYER - ******************************************************************************/ - -/* From dev up to socket */ -int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto); - -/******************************************************************************* - * NETWORK LAYER - ******************************************************************************/ - -/* From socket down to dev */ -int32_t pico_network_send(struct pico_frame *f); - -/* From dev up to socket */ -int32_t pico_network_receive(struct pico_frame *f); - -/******************************************************************************* - * DATALINK LAYER - ******************************************************************************/ - -/* From socket down to dev */ -int pico_datalink_send(struct pico_frame *f); - -/* From dev up to socket */ -int pico_datalink_receive(struct pico_frame *f); - -/******************************************************************************* - * PHYSICAL LAYER - ******************************************************************************/ - -/* Enqueues the frame in the device-queue. From socket down to dev */ -int32_t pico_sendto_dev(struct pico_frame *f); - -/* LOWEST LEVEL: interface towards stack from 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() - */ - -#ifdef __cplusplus -extern "C" { -#endif - -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)); -struct pico_frame *pico_stack_recv_new_frame(struct pico_device *dev, uint8_t *buffer, uint32_t len); - -/* ----- Initialization ----- */ -int pico_stack_init(void); - -/* ----- Loop Function. ----- */ -void pico_stack_tick(void); -void pico_stack_loop(void); - -#ifdef __cplusplus -} -#endif - -/* ---- 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); - -#ifdef __cplusplus -extern "C" { -#endif - -int pico_ntimers(); - -#ifdef __cplusplus -} -#endif - -/* 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); -uint32_t pico_timer_add_hashed(pico_time expire, void (*timer)(pico_time, void *), void *arg, uint32_t hash); -void pico_timer_cancel_hashed(uint32_t hash); -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 9d826c0..0000000 --- a/ext/picotcp/include/pico_tree.h +++ /dev/null @@ -1,93 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 6e536bc..0000000 --- a/ext/picotcp/mkdeps.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [ "$#" -eq 0 ]; then - echo "Supply PREFIX for building pico_defines.h" - exit 1 -fi - -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 068e170..0000000 --- a/ext/picotcp/modcheck.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/python -import os,sys -import subprocess - - -print "Scroll down for summary" -print "" -print "" - -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) - -endResult = [] -failed = 0 - -for i in commands: - print 'Checking config:\n\t%s' % i - - subprocess.call(['make','clean']) - sys.stdout.flush() - sys.stderr.flush() - - args = i.split(' ') - - # Remove the last item (which is a blank) - ret = subprocess.call(args[:-1]) - sys.stdout.flush() - sys.stderr.flush() - - if ret == 0: - print "**********************************************************" - print "******************* CONFIG PASSED! *******************" - endResult.append({"test": i, "result": "PASS"}) - else: - failed += 1 - print "**********************************************************" - print "******************* CONFIG FAILED! *******************" - endResult.append({"test": i, "result": "FAIL"}) - print "**********************************************************" - -print "" -print "***************************************************************************" -print " Executive Summary" -print "***************************************************************************" -print "" - -for r in endResult: - print "Test:", r["test"] - print "Status:", r["result"] - print "" - -print "***********************" -print "%d out of %d Failed" % (failed, len(endResult)) -print "***********************" - -if failed: - sys.exit(1) -else: - sys.exit(0) diff --git a/ext/picotcp/modules/pico_6lowpan.c b/ext/picotcp/modules/pico_6lowpan.c deleted file mode 100644 index c4eb2e0..0000000 --- a/ext/picotcp/modules/pico_6lowpan.c +++ /dev/null @@ -1,1647 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -#include "pico_udp.h" -#include "pico_ipv6.h" -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_6lowpan.h" -#include "pico_protocol.h" -#include "pico_addressing.h" -#include "pico_6lowpan_ll.h" - -#ifdef PICO_SUPPORT_6LOWPAN - -/******************************************************************************* - * Macros - ******************************************************************************/ - -#ifdef DEBUG_6LOWPAN -#define GRN "\x1b[32m" -#define ORG "\x1b[33m" -#define RST "\x1b[0m" -#define lp_dbg dbg -#else -#define lp_dbg(...) do {} while(0) -#endif - -#define IPV6_MCAST_48(addr) (!addr[8] && !addr[9] && !addr[10] && (addr[11] || addr[12])) -#define IPV6_MCAST_32(addr) (!addr[8] && !addr[9] && !addr[10] && !addr[11] && !addr[12] && (addr[13] || addr[14])) -#define IPV6_MCAST_8(addr) (addr[1] == 0x02 && !addr[14] && addr[15]) -#define PORT_COMP(a, mask, b) (((a) & (mask)) == (b)) - -/******************************************************************************* - * Constants - ******************************************************************************/ - -#define NUM_IPV6_FIELDS (6) -#define NUM_UDP_FIELDS (4) -#define IPV6_DISPATCH (0x41) -#define IPHC_DISPATCH (0x60) -#define UDP_DISPATCH (0xF0) -#define EXT_DISPATCH (0xE0) -#define EXT_HOPBYHOP (0x00) -#define EXT_ROUTING (0x02) -#define EXT_FRAG (0x04) -#define EXT_DSTOPT (0x06) -#define EXT_COMPRESSED_NH (0x01) -#define UDP_COMPRESSED_DST (0x01) -#define UDP_COMPRESSED_SRC (0x02) -#define UDP_COMPRESSED_BOTH (0x03) -#define UDP_COMPRESSED_CHCK (0x04) -#define TF_INLINE (0x00) -#define TF_ELIDED_DSCP (0x08) -#define TF_ELIDED_FL (0x10) -#define TF_ELIDED (0x18) -#define NH_COMPRESSED (0x04) -#define HL_COMPRESSED_1 (0x01) -#define HL_COMPRESSED_64 (0x02) -#define HL_COMPRESSED_255 (0x03) -#define CTX_EXTENSION (0x80) -#define SRC_SHIFT (0x04) -#define SRC_STATEFUL (0x40) -#define SRC_COMPRESSED_64 (0x10) -#define SRC_COMPRESSED_16 (0x20) -#define SRC_COMPRESSED (0x30) -#define DST_STATEFUL (0x04) -#define DST_COMPRESSED_64 (0x01) -#define DST_COMPRESSED_16 (0x02) -#define DST_COMPRESSED (0x03) -#define DST_MULTICAST (0x08) -#define DST_MCAST_48 (0x01) -#define DST_MCAST_32 (0x02) -#define DST_MCAST_8 (0x03) -#define COMP_LINKLOCAL (0) -#define COMP_STATELESS (-1) -#define COMP_MULTICAST (-2) -#define COMP_UNSPECIFIED (-3) -#define FRAG1_SIZE (4) -#define FRAGN_SIZE (5) -#define FRAG1_DISPATCH (0xC0) -#define FRAGN_DISPATCH (0xE0) -#define FRAG_TIMEOUT (5) -/******************************************************************************* - * Type definitions - ******************************************************************************/ - -struct hdr_field -{ - int8_t ori_size; - int8_t (* compress)(uint8_t *, uint8_t *, uint8_t *, union pico_ll_addr *, union pico_ll_addr *, struct pico_device *); - int8_t (* decompress)(uint8_t *, uint8_t *, uint8_t *, union pico_ll_addr *, union pico_ll_addr *, struct pico_device *); -}; - -struct frag_ctx { - struct pico_frame *f; - uint16_t dgram_size; - uint16_t dgram_tag; - uint8_t dgram_off; - uint16_t copied; - uint32_t hash; - pico_time timestamp; -}; - -/******************************************************************************* - * Global Variables - ******************************************************************************/ - -static struct pico_queue pico_6lowpan_in = { - 0 -}; -static struct pico_queue pico_6lowpan_out = { - 0 -}; - -static uint16_t dgram_tag = 0; - -/******************************************************************************* - * Private functions - ******************************************************************************/ - -/* Copies two memory buffers but also considers overlapping buffers */ -static void -buf_move(void *dst, const void *src, size_t len) -{ - uint8_t *d = (uint8_t *)dst; - const uint8_t *s = (const uint8_t *)src; - if (!dst || !src) { - return; - } else { - if (d < s) { - while (len--) - *d++ = *s++; - } else { - s = s + len - 1; - d = d + len - 1; - while (len--) - *d-- = *s--; - } - } -} - -/******************************************************************************* - * Frags - ******************************************************************************/ - -/* Compares two fragmentation cookies based on the hash */ -static int32_t -frag_ctx_cmp(void *a, void *b) -{ - struct frag_ctx *fa = (struct frag_ctx *)a; - struct frag_ctx *fb = (struct frag_ctx *)b; - return (int32_t)(fa->hash - fb->hash); -} - -/* Compares two fragmentation cookies according to RFC4944 5.3 */ -static int32_t -frag_cmp(void *a, void *b) -{ - struct frag_ctx *fa = (struct frag_ctx *)a; - struct frag_ctx *fb = (struct frag_ctx *)b; - int32_t ret = 0; - if (fa->dgram_size != fb->dgram_size) { - return (int32_t)(fa->dgram_size - fb->dgram_size); - } else if (fa->dgram_tag != fb->dgram_tag) { - return (int32_t)(fa->dgram_tag - fb->dgram_tag); - } else { - if ((ret = pico_6lowpan_lls[fa->f->dev->mode].addr_cmp(&fa->f->src, &fb->f->src))) { - return ret; - } else { - return pico_6lowpan_lls[fa->f->dev->mode].addr_cmp(&fa->f->dst, &fb->f->dst); - } - } -} - -PICO_TREE_DECLARE(FragTree, &frag_ctx_cmp); -PICO_TREE_DECLARE(ReassemblyTree, &frag_cmp); - -/* Find a fragmentation cookie for transmission of subsequent fragments */ -static struct frag_ctx * -frag_ctx_find(uint32_t hash) -{ - struct frag_ctx f = { .hash = hash }; - return pico_tree_findKey(&FragTree, &f); -} - -/* Reassembly timeout function, deletes */ -static void -frag_timeout(pico_time now, void *arg) -{ - struct pico_tree_node *i = NULL, *next = NULL; - struct frag_ctx *key = NULL; - IGNORE_PARAMETER(arg); - pico_tree_foreach_safe(i, &ReassemblyTree, next) { - if ((key = i->keyValue)) { - if ((pico_time)(FRAG_TIMEOUT * 1000) <= (now - key->timestamp)) { - lp_dbg("Timeout for reassembly: %d\n", key->dgram_tag); - pico_tree_delete(&ReassemblyTree, key); - pico_frame_discard(key->f); - PICO_FREE(key); - } - } - } - - /* If adding a timer fails, there's not really an easy way to recover, so abort all ongoing - * reassemblies - * TODO: Maybe using a global variable allows recovering from this situation */ - if (0 == pico_timer_add(1000, frag_timeout, NULL)) { - lp_dbg("6LP: Failed to set reassembly timeout! Aborting all ongoing reassemblies...\n"); - pico_tree_foreach_safe(i, &ReassemblyTree, next) { - if ((key = i->keyValue)) { - pico_tree_delete(&ReassemblyTree, key); - pico_frame_discard(key->f); - PICO_FREE(key); - } - } - } -} - -/* Finds a reassembly cookie in the reassembly-tree */ -static struct frag_ctx * -frag_find(uint16_t dgram_size, uint16_t tag, struct pico_frame *frame) -{ - struct frag_ctx f = {.f = frame, .dgram_size = dgram_size, .dgram_tag = tag}; - return pico_tree_findKey(&ReassemblyTree, &f); -} - -/* Stores a fragmentation cookie in either the fragmentetion cookie tree or - * in the reassembly tree */ -static int32_t -frag_store(struct pico_frame *f, uint16_t dgram_size, uint16_t tag, - uint8_t dgram_off, uint16_t copied, struct pico_tree *tree) -{ - struct frag_ctx *fr = PICO_ZALLOC(sizeof(struct frag_ctx)); - if (fr) { - fr->f = f; - fr->dgram_size = dgram_size; - fr->dgram_off = dgram_off; - fr->dgram_tag = tag; - fr->copied = copied; - fr->timestamp = PICO_TIME_MS(); - if (&FragTree == tree) { - fr->hash = pico_hash((void *)fr, sizeof(struct frag_ctx)); - f->hash = fr->hash; // Also set hash in frame so we can identify it - lp_dbg("6LP: START: "ORG"fragmentation"RST" with hash '%X' of %u bytes.\n", fr->hash, f->len); - } else { - lp_dbg("6LP: START: "GRN"reassembly"RST" with tag '%d' of %u bytes.\n", tag, dgram_size); - } - /* Insert the cookie in the appropriate tree (FragTree/ReassemblyTree) */ - if (pico_tree_insert(tree, fr)) { - PICO_FREE(fr); - return -1; - } - } else { - return (-1); - } - return (1); // Succes for 'proto_loop_out' -} - -/******************************************************************************* - * IPHC - ******************************************************************************/ - -#ifdef PICO_6LOWPAN_IPHC_ENABLED - -/* Compresses the VTF-field of an IPv6 header */ -static int8_t -compressor_vtf(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr * - llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - uint8_t ecn = 0, dscp = 0; - uint32_t fl = 0; - *ori &= 0x0F; // Clear version field - *iphc &= (uint8_t)0x07; // Clear IPHC field - *iphc |= (uint8_t)IPHC_DISPATCH; - IGNORE_PARAMETER(llsrc); - IGNORE_PARAMETER(lldst); - IGNORE_PARAMETER(dev); - - /* Don't worry... */ - ecn = (uint8_t)((ori[0] << 4) & 0xC0); - dscp = (uint8_t)(((ori[0] << 4) & 0x30) | ((ori[1] & 0xF0) >> 4)); - fl = long_be((uint32_t)(ori[1] & 0x0F) << 16); - fl += long_be((uint32_t)(ori[2] & 0xFF) << 8); - fl += long_be((uint32_t)(ori[3] & 0xFF)); - - if (fl) { - if (!dscp) { // Flow label carried in-line - *iphc |= TF_ELIDED_DSCP; - comp[0] = (uint8_t)(ecn | (ori[1] & 0x0F)); - comp[1] = ori[2]; - comp[2] = ori[3]; - return 3; - } else { // Traffic class and flow label carried in-line - *iphc |= TF_INLINE; - *comp = ecn | dscp; - comp[1] = ori[1] & 0x0F; - comp[2] = ori[2]; - comp[3] = ori[3]; - return 4; - } - } else if (ecn || dscp) { // Traffic class carried in-line - *iphc |= TF_ELIDED_FL; - *comp = ecn | dscp; - return 1; - } else { // Traffic class and flow label elided - *iphc |= TF_ELIDED; - return 0; - } -} - -/* Decompresses the VTF-field of a IPHC-header */ -static int8_t -decompressor_vtf(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr - *llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - uint8_t tf = *iphc & TF_ELIDED; - IGNORE_PARAMETER(llsrc); - IGNORE_PARAMETER(lldst); - IGNORE_PARAMETER(dev); - if (TF_INLINE == tf) { - *ori++ = (0x60 | (*comp >> 4)); - *ori |= (uint8_t)((uint8_t)(*comp++ << 4) & 0xF0); - *ori++ |= *comp++; - *ori++ = *comp++; - *ori++ = *comp++; - return 4; - } else if (TF_ELIDED_DSCP == tf) { - *ori++ = (0x60 | (*comp >> 4)) & 0xFC; - *ori++ = *comp++ & 0x0F; - *ori++ = *comp++; - *ori = *comp; - return 3; - } else if (TF_ELIDED_FL == tf) { - *ori++ = (0x60 | (*comp >> 4)); - *ori = (uint8_t)(*comp << 4) & 0xF0; - return 1; - } else { - *ori = 0x60; // Set version field to IPv6 - return 0; - } -} - -/* Checks whether or not next header is compressible according to NHC scheme */ -static int32_t -compressible_nh(uint8_t nh) -{ - switch (nh) { - case PICO_IPV6_EXTHDR_HOPBYHOP: - case PICO_IPV6_EXTHDR_ROUTING: - case PICO_IPV6_EXTHDR_FRAG: - case PICO_IPV6_EXTHDR_DESTOPT: - case PICO_PROTO_UDP: return 1; - default: return 0; - } -} - -/* Checks whether or not the next header can be compressed and sets the IPHC - * bits accordingly, compression of next header itself happens in NHC-compression - */ -static int8_t -compressor_nh(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr * - llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - *iphc &= (uint8_t)~NH_COMPRESSED; - IGNORE_PARAMETER(comp); - IGNORE_PARAMETER(llsrc); - IGNORE_PARAMETER(lldst); - IGNORE_PARAMETER(dev); - if (compressible_nh(*ori)) { - *iphc |= NH_COMPRESSED; - return 0; - } else { - *comp = *ori; - return 1; - } -} - -/* Check whether or no the next header is NHC-compressed, indicates this for the - * general decompressor so it knows that it has to decompress the next header - * and fill in the NH-header field in IPv6 header */ -static int8_t -decompressor_nh(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr - *llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - IGNORE_PARAMETER(llsrc); - IGNORE_PARAMETER(lldst); - IGNORE_PARAMETER(dev); - IGNORE_PARAMETER(comp); - if (*iphc & NH_COMPRESSED) { - *ori = 0; // Indicate that next header needs to be decompressed - return 0; - } else { - *ori = *comp; - return 1; - } -} - -/* Compressed the HL-field if common hop limit values are used, like 1, 64 and - * 255 */ -static int8_t -compressor_hl(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr * - llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - IGNORE_PARAMETER(llsrc); - IGNORE_PARAMETER(lldst); - IGNORE_PARAMETER(dev); - *iphc &= (uint8_t)~HL_COMPRESSED_255; - switch (*ori) { - case 1: *iphc |= (uint8_t)HL_COMPRESSED_1; - return 0; - case 64: *iphc |= (uint8_t)HL_COMPRESSED_64; - return 0; - case 255: *iphc |= (uint8_t)HL_COMPRESSED_255; - return 0; - default: *comp = *ori; - return 1; - } -} - -/* Decompresses the HL-field to common hop limit values like 1, 64 and 255 */ -static int8_t -decompressor_hl(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr - *llsrc, union pico_ll_addr *lldst, struct pico_device *dev) - -{ - uint8_t hl = *iphc & HL_COMPRESSED_255; - IGNORE_PARAMETER(llsrc); - IGNORE_PARAMETER(lldst); - IGNORE_PARAMETER(dev); - switch(hl) { - case HL_COMPRESSED_1: *ori = (uint8_t)1; - return 0; - case HL_COMPRESSED_64: *ori = (uint8_t)64; - return 0; - case HL_COMPRESSED_255: *ori = (uint8_t)255; - return 0; - default: *ori = *comp; - return 1; - } -} - -/* Determines if an address can be statefully or statelessly compressed */ -static int8_t -addr_comp_prefix(uint8_t *iphc, struct pico_ip6 *addr, int8_t src) -{ - struct iphc_ctx *ctx = NULL; - uint8_t state = src ? SRC_STATEFUL : DST_STATEFUL; - iphc[1] &= (uint8_t)~state; // Clear out compression state for src/dst - - if (pico_ipv6_is_multicast(addr->addr)) { - /* TODO: Support stateful multicast compression with Unicast-Prefix-Based - * IPv6 Multicast Addresses as defined in RFC3956 */ - return COMP_MULTICAST; // AC = 0 - } else if (pico_ipv6_is_linklocal(addr->addr)) { - return COMP_LINKLOCAL; // AC = 0 - } else if ((ctx = ctx_lookup(*addr))) { - if (ctx->flags & PICO_IPHC_CTX_COMPRESS) { - iphc[1] |= state; // AC = 1 - iphc[1] |= CTX_EXTENSION; // SRC or DST is stateful, CID = 1 - return (int8_t)ctx->id; - } - } - return COMP_STATELESS; // AC = 0 -} - -/* Checks whether or not an IPv6 address is derived from a link layer address */ -static int8_t -addr_ll_derived(struct pico_ip6 *addr, union pico_ll_addr *lladdr, struct pico_device *dev) -{ - uint8_t iid[8] = {0}; - if (pico_6lowpan_lls[dev->mode].addr_iid) { - if (!pico_6lowpan_lls[dev->mode].addr_iid(iid, lladdr)) - return (int8_t)(0 == memcmp(iid, &addr->addr[8], 8)); - } - return -1; -} - -/* Sets the compression mode of either the source address or the destination - * address, based on the shift parameter. Use SRC_SHIFT for source, 0 for dst */ -static int8_t -addr_comp_mode(uint8_t *iphc, struct pico_ip6 *addr, union pico_ll_addr lladdr, struct pico_device *dev, int8_t shift) -{ - int8_t mac = addr_ll_derived(addr, &lladdr, dev); - iphc[1] &= (uint8_t)((uint8_t)~DST_COMPRESSED << shift); // Clear src/dst mode - - if (mac > 0) { // Address is mac derived - iphc[1] |= (uint8_t)(DST_COMPRESSED << shift); - return 0; - } else if (!mac && IID_16(&addr->addr[8])) { // Address is 16-bit deriveable - iphc[1] |= (uint8_t)(DST_COMPRESSED_16 << shift); - return 2; - } else if (!mac) { // Copy the entire IID - iphc[1] |= (uint8_t)(DST_COMPRESSED_64 << shift); - return 8; - } else { - return -1; // Something went wrong, indicate failure - } -} - -/* Compresses a multicast address statelessly */ -static int8_t -addr_comp_mcast(uint8_t *iphc, uint8_t *comp, struct pico_ip6 *mcast) -{ - iphc[1] &= (uint8_t)~DST_MCAST_8; // Clear out addressing mode - iphc[1] |= (uint8_t)DST_MULTICAST; // Set multicast flag - - if (IPV6_MCAST_48(mcast->addr)) { - comp[0] = mcast->addr[1]; // Copy flags and scope - buf_move(&comp[1], &mcast->addr[11], 5); // Copy group identifier - iphc[1] |= DST_MCAST_48; - return 6; - } else if (IPV6_MCAST_32(mcast->addr)) { - comp[0] = mcast->addr[1]; // Copy flags and scope - buf_move(&comp[1], &mcast->addr[13], 3); // Copy group identifier - iphc[1] |= DST_MCAST_32; - return 4; - } else if (IPV6_MCAST_8(mcast->addr)) { - comp[0] = mcast->addr[15]; // Copy group identifier - iphc[1] |= DST_MCAST_8; // Flags and scope = 0x02 - return 1; - } else { - buf_move(comp, mcast->addr, PICO_SIZE_IP6); // Copy entire address - return PICO_SIZE_IP6; - } -} - -/* Compresses the IID of a IPv6 address into 'comp'. Also has to take link layer - * address into account and whether it's about source or destination address. */ -static int8_t -addr_comp_iid(uint8_t *iphc, uint8_t *comp, int8_t state, struct pico_ip6 *addr, union pico_ll_addr ll, struct pico_device *dev, int8_t shift) -{ - int8_t len = PICO_SIZE_IP6; - switch (state) { - case COMP_UNSPECIFIED: // Set stateful bit - iphc[1] |= SRC_STATEFUL; - case COMP_STATELESS: // Clear compressed flags - iphc[1] &= (uint8_t)~SRC_COMPRESSED; - break; - case COMP_LINKLOCAL: - len = addr_comp_mode(iphc, addr, ll, dev, shift); - break; - case COMP_MULTICAST: // Multicast, compress statelessly - return addr_comp_mcast(iphc, comp, addr); - default: // Context available, extend header, and check for IID - iphc[2] = (uint8_t)((uint8_t)state << shift); - len = addr_comp_mode(iphc, addr, ll, dev, shift); - } - - if (len >= 0) - buf_move(comp, addr->addr + PICO_SIZE_IP6 - len, (size_t)len); - return len; -} - -/* Compresses the SOURCE address of the IPv6 frame */ -static int8_t -compressor_src(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr *llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - struct pico_ip6 src = *(struct pico_ip6 *)ori; - int8_t ret = addr_comp_prefix(iphc, &src, SRC_SHIFT); - IGNORE_PARAMETER(lldst); - - if (pico_ipv6_is_unspecified(src.addr)) - ret = COMP_UNSPECIFIED; - - return addr_comp_iid(iphc, comp, ret, &src, *llsrc, dev, SRC_SHIFT); -} - -/* Copies the appropriate IPv6 prefix in the decompressed address. Based on - * context, link local address or multicast address */ -static int8_t -addr_decomp_prefix(uint8_t *prefix, uint8_t *iphc, int8_t shift) -{ - struct pico_ip6 ll = { .addr = {0xfe,0x80,0,0,0,0,0,0,0,0,0,0xff,0xfe,0,0,0}}; - uint8_t addr_state = (uint8_t)(DST_STATEFUL << shift); - struct iphc_ctx *ctx = NULL; - - if (iphc[1] & addr_state) { - if ((ctx = ctx_lookup_id((uint8_t)(iphc[2] >> shift)))) { - buf_move(prefix, ctx->prefix.addr, PICO_SIZE_IP6); - buf_move(&prefix[8], &ll.addr[8], 8); // For 16-bit derived addresses - } else { - /* No context available while stateful compression is used... */ - return -1; - } - } else { - buf_move(prefix, ll.addr, PICO_SIZE_IP6); - } - return 0; -} - -/* Decompresses the IID of the IPv6 address based on addressing mode of the IPHC- - * header */ -static int8_t -addr_decomp_iid(struct pico_ip6 *addr, uint8_t *comp, uint8_t am, union pico_ll_addr lladdr, struct pico_device *dev) -{ - if (addr) { - switch (am) { - case DST_COMPRESSED_64: buf_move(&addr->addr[8], comp, 8); - return 8; - case DST_COMPRESSED_16: buf_move(&addr->addr[14], comp, 2); - return 2; - case DST_COMPRESSED: - if (dev && pico_6lowpan_lls[dev->mode].addr_iid) { - pico_6lowpan_lls[dev->mode].addr_iid(&addr->addr[8], &lladdr); - return 0; - } else { - return -1; - } - default: buf_move(addr->addr, comp, PICO_SIZE_IP6); - return 16; - } - } else { - return -1; - } -} - -/* Decompress the SOURCE address of the 6LoWPAN frame */ -static int8_t -decompressor_src(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr - *llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - struct pico_ip6 *src = (struct pico_ip6 *)ori; - uint8_t sam = (uint8_t)((uint8_t)(iphc[1] & SRC_COMPRESSED) >> 4); - IGNORE_PARAMETER(lldst); - - /* Get the appropriate IPv6 prefix */ - if (addr_decomp_prefix(ori, iphc, SRC_SHIFT)) - return -1; - - return addr_decomp_iid(src, comp, sam, *llsrc, dev); -} - -/* Compresses the DESTINATION address of IPv6 frame */ -static int8_t -compressor_dst(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr * - llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - struct pico_ip6 dst = *(struct pico_ip6 *)ori; - int8_t ret = addr_comp_prefix(iphc, &dst, 0); - IGNORE_PARAMETER(llsrc); - return addr_comp_iid(iphc, comp, ret, &dst, *lldst, dev, 0); -} - -/* Decompresses the IPv6 multicast destination address when the IPHC mcast-flag - * is set */ -static int8_t -addr_decomp_mcast(uint8_t *comp, struct pico_ip6 *dst, uint8_t am) -{ - if (dst) { - memset(dst->addr, 0, PICO_SIZE_IP6); - dst->addr[0] = 0xff; - dst->addr[1] = *comp; - switch (am) { - case DST_MCAST_48: - buf_move(dst->addr + 11, comp + 1, 5); - return 6; - case DST_MCAST_32: - buf_move(dst->addr + 13, comp + 1, 3); - return 4; - case DST_MCAST_8: - dst->addr[1] = 0x02; - dst->addr[15] = *comp; - return 1; - default: - buf_move(dst->addr, comp, PICO_SIZE_IP6); - return PICO_SIZE_IP6; - } - } else { - return -1; - } -} - -/* Decompresses the DESTINATION address of a 6LoWPAN frame */ -static int8_t -decompressor_dst(uint8_t *ori, uint8_t *comp, uint8_t *iphc, union pico_ll_addr *llsrc, union pico_ll_addr *lldst, struct pico_device *dev) -{ - struct pico_ip6 *dst = (struct pico_ip6 *)ori; - uint8_t dam = iphc[1] & DST_COMPRESSED; - IGNORE_PARAMETER(llsrc); - - if (addr_decomp_prefix(ori, iphc, SRC_SHIFT)) - return -1; - - if (iphc[1] & DST_MULTICAST) { - return addr_decomp_mcast(comp, dst, dam); - } else { - return addr_decomp_iid(dst, comp, dam, *lldst, dev); - } -} - -static const struct hdr_field ip6_fields[] = { - {4, compressor_vtf, decompressor_vtf}, - {2, NULL, NULL}, - {1, compressor_nh, decompressor_nh}, - {1, compressor_hl, decompressor_hl}, - {16, compressor_src, decompressor_src}, - {16, compressor_dst, decompressor_dst} -}; - -/* Compresses the IPv6 frame according to the IPHC-compression scheme */ -static uint8_t * -compressor_iphc(struct pico_frame *f, int32_t *compressed_len, uint8_t *nh) -{ - uint8_t *inline_buf = PICO_ZALLOC(PICO_SIZE_IP6HDR + 3); - uint8_t *comp = inline_buf + 3; - uint8_t *iphc = inline_buf; - uint8_t *ori = f->net_hdr; - int32_t i = 0, ret = 0; - *compressed_len = 0; - *nh = ((struct pico_ipv6_hdr *)f->net_hdr)->nxthdr; - - if (!inline_buf) { - return NULL; - } else { - /* Compress fixed IPv6 fields */ - for (i = 0; i < NUM_IPV6_FIELDS; i++) { - if (ip6_fields[i].compress) { - ret = ip6_fields[i].compress(ori, comp, iphc, &f->src, &f->dst, f->dev); - if (ret < 0) { // Something went wrong ... - PICO_FREE(inline_buf); - return NULL; - } - *compressed_len += ret; // Increase compressed length - comp += ret; // Move forward compressed length - } - ori += ip6_fields[i].ori_size; // Move to next field - } - - /* Rearrange IPHC-header if CTX-extension is included */ - if (iphc[1] & CTX_EXTENSION) { - *compressed_len += 3; - } else { - buf_move(inline_buf + 2, inline_buf + 3, (size_t)*compressed_len); - *compressed_len += 2; - } - } - return inline_buf; -} - -/* Decompresses a frame compressed with the IPHC compression scheme, RFC6282 */ -static uint8_t * -decompressor_iphc(struct pico_frame *f, int32_t *compressed_len) -{ - uint8_t *ipv6_hdr = PICO_ZALLOC(PICO_SIZE_IP6HDR); - uint8_t *iphc = f->net_hdr, *ori = ipv6_hdr, *comp = NULL; - int32_t i = 0, ret = 0, ctx = f->net_hdr[1] & CTX_EXTENSION; - *compressed_len = ctx ? 3 : 2; - comp = f->net_hdr + (ctx ? 3 : 2); - - if (!ipv6_hdr) { - return NULL; - } else { - for (i = 0; i < NUM_IPV6_FIELDS; i++) { - if (ip6_fields[i].decompress) { - ret = ip6_fields[i].decompress(ori, comp, iphc, &f->src, &f->dst, f->dev); - if (ret < 0) { // Something went wrong ... - PICO_FREE(ipv6_hdr); - return NULL; - } - *compressed_len += ret; // Increase compressed size - comp += ret; // Move to next compressed chunk - } - ori += ip6_fields[i].ori_size; // Move to next IPv6 field - } - } - return ipv6_hdr; -} - -/* Compresses a UDP header according to the NHC_UDP compression scheme, RFC6282 */ -static uint8_t * -compressor_nhc_udp(struct pico_frame *f, int32_t *compressed_len) -{ - uint8_t *inline_buf = PICO_ZALLOC(PICO_UDPHDR_SIZE); - struct pico_udp_hdr *hdr = (struct pico_udp_hdr *)f->transport_hdr; - uint16_t sport = hdr->trans.sport, dport = hdr->trans.dport; - uint16_t xF0B0 = short_be(0xF0B0), xF000 = short_be(0xF000); - uint16_t xFF00 = short_be(0xFF00), xFFF0 = short_be(0xFFF0); - *compressed_len = 0; - - if (!inline_buf) { - return NULL; - } else { - /* Dispatch header */ - inline_buf[0] = (uint8_t)UDP_DISPATCH; - /* Port compression */ - if (PORT_COMP(sport, xFFF0, xF0B0) && PORT_COMP(dport, xFFF0, xF0B0)) { - inline_buf[0] |= UDP_COMPRESSED_BOTH; - inline_buf[1] = (uint8_t)(short_be(sport) << 4); - dport = (uint8_t)(short_be(dport) & (uint16_t)0x000F); - inline_buf[1] = (uint8_t)(inline_buf[1] | (uint8_t)dport); - *compressed_len = 2; - } else if (PORT_COMP(sport, xFF00, xF000)) { - inline_buf[0] |= UDP_COMPRESSED_SRC; - inline_buf[1] = (uint8_t)short_be(sport); - buf_move(inline_buf + 2, (uint8_t *)hdr + 2, 2); - *compressed_len = 4; - } else if (PORT_COMP(dport, xFF00, xF000)) { - inline_buf[0] |= UDP_COMPRESSED_DST; - inline_buf[3] = (uint8_t)short_be(dport); - buf_move(inline_buf + 1, (uint8_t *)hdr, 2); - *compressed_len = 4; - } else { - inline_buf[0] &= (uint8_t)~UDP_COMPRESSED_BOTH; - buf_move(inline_buf + 1, (uint8_t *)hdr, 4); - *compressed_len = 5; - } - /* Length MUST be compressed checksum carried inline. - * RFC6282: .., a compressor in the source transport endpoint MAY elide - * the UDP checksum if it is autorized by the upper layer. The compressor - * MUST NOT set the C bit unless it has received such authorization */ - buf_move(inline_buf + *compressed_len, (uint8_t *)hdr + 6, 2); - *compressed_len += 2; - return inline_buf; - } -} - -/* Decompresses a NHC_UDP header according to the NHC_UDP compression scheme */ -static uint8_t * -decompressor_nhc_udp(struct pico_frame *f, int32_t processed_len, int32_t *compressed_len) -{ - struct pico_udp_hdr *hdr = NULL; - uint8_t *buf = f->transport_hdr; - uint8_t compression = buf[0] & UDP_COMPRESSED_BOTH; - uint16_t xF0B0 = short_be(0xF0B0); - uint16_t xF000 = short_be(0xF000); - int32_t payload_len = 0; - *compressed_len = 0; - - /* Decompress ports */ - hdr = PICO_ZALLOC(PICO_UDPHDR_SIZE); - if (hdr) { - if (UDP_COMPRESSED_BOTH == compression) { - hdr->trans.sport = xF0B0 | short_be((uint16_t)(buf[1] >> 4)); - hdr->trans.dport = xF0B0 | short_be((uint16_t)(buf[1] & 0xff)); - *compressed_len = 2; - } else if (UDP_COMPRESSED_SRC == compression) { - hdr->trans.dport = short_be((uint16_t)(((uint16_t)buf[2] << 8) | (uint16_t)buf[3])); - hdr->trans.sport = xF000 | short_be((uint16_t)buf[1]); - *compressed_len = 4; - } else if (UDP_COMPRESSED_DST == compression) { - hdr->trans.sport = short_be((uint16_t)(((uint16_t)buf[1] << 8) | (uint16_t)buf[2])); - hdr->trans.dport = xF000 | short_be((uint16_t)buf[3]); - *compressed_len = 4; - } else { - buf_move((uint8_t *)&hdr->trans, &buf[1], 4); - *compressed_len = 5; - } - if (!(buf[0] & UDP_COMPRESSED_CHCK)) { // Leave empty room for checksum - buf_move((uint8_t *)&hdr->crc, &buf[*compressed_len],2); - *compressed_len += 2; - } - /* Restore inherently compressed length */ - payload_len = (int32_t)f->len - (processed_len + *compressed_len); - hdr->len = short_be((uint16_t)(payload_len + PICO_UDPHDR_SIZE)); - return (uint8_t *)hdr; - } - return NULL; -} - -/* Get's the length of an IPv6 extension header */ -static int32_t -ext_hdr_len(struct pico_ipv6_exthdr *ext, uint8_t hdr, uint8_t *dispatch) -{ - int32_t len = 0; - /* Get length of extension header */ - switch (hdr) { - case PICO_IPV6_EXTHDR_HOPBYHOP: - *dispatch |= (uint8_t)EXT_HOPBYHOP; - len = IPV6_OPTLEN(ext->ext.destopt.len); // Length in bytes - ext->ext.destopt.len = (uint8_t)(len - 2); // Octets after len-field - return (int32_t)len; - case PICO_IPV6_EXTHDR_ROUTING: - *dispatch |= (uint8_t)EXT_ROUTING; - len = IPV6_OPTLEN(ext->ext.destopt.len); // Length in bytes - ext->ext.destopt.len = (uint8_t)(len - 2); // Octets after len-field - return (int32_t)len; - case PICO_IPV6_EXTHDR_DESTOPT: - *dispatch |= (uint8_t)EXT_DSTOPT; - len = IPV6_OPTLEN(ext->ext.destopt.len); // Length in bytes - ext->ext.destopt.len = (uint8_t)(len - 2); // Octets after len-field - return (int32_t)len; - case PICO_IPV6_EXTHDR_FRAG: - *dispatch |= (uint8_t)EXT_FRAG; - return (int32_t)8; - default: // Somethin went wrong, bail out... - return -1; - } -} - -/* Compresses an IPv6 extension header according to the NHC_EXT compression - * scheme */ -static uint8_t * -compressor_nhc_ext(struct pico_frame *f, int32_t *compressed_len, uint8_t *nh) -{ - struct pico_ipv6_exthdr *ext = (struct pico_ipv6_exthdr *)f->net_hdr; - uint8_t dispatch = EXT_DISPATCH; - int32_t len = 0, lead = 0, ret = 0; - uint8_t *buf = NULL; - uint8_t hdr = *nh; - - /* Determine next header */ - *nh = ext->nxthdr; - if (!compressible_nh(*nh)) { - len++; // Dispatch header has to be prepended - lead++; // Copy right after dispatch - } else { - dispatch |= (uint8_t)0x01; // Set NH flag - } - - /* Get length of extension header */ - ret = ext_hdr_len(ext, hdr, &dispatch); - if (ret < 0) { - return NULL; - } else { - /* Provide inline buffer */ - len += ret; - buf = PICO_ZALLOC((size_t)len); - if (!buf) { - return NULL; - } else { - /* Copy extension header */ - buf_move(buf + lead, (uint8_t *)ext, (size_t)(len - lead)); - buf[0] = dispatch; // Set the dispatch header - *compressed_len = len; - f->net_hdr += *compressed_len; // Move to next header - return buf; - } - } -} - -/* Retrieves the next header from the immediately following header */ -static uint8_t -ext_nh_retrieve(uint8_t *buf, int32_t len) -{ - uint8_t eid = 0; - buf += len; - if ((buf[0] & 0xF0) == EXT_DISPATCH) { - eid = buf[0] & 0x0E; - switch (eid) { - case EXT_HOPBYHOP: - return (uint8_t)PICO_IPV6_EXTHDR_HOPBYHOP; - case EXT_ROUTING: - return (uint8_t)PICO_IPV6_EXTHDR_ROUTING; - case EXT_FRAG: - return (uint8_t)PICO_IPV6_EXTHDR_FRAG; - case EXT_DSTOPT: - return (uint8_t)PICO_IPV6_EXTHDR_DESTOPT; - default: - return 0; - } - } else if ((buf[0] & 0xF8) == UDP_DISPATCH) { - return PICO_PROTO_UDP; - } - return 0; -} - -/* RFC6282: A decompressor MUST ensure that the - * containing header is padded out to a multiple of 8 octets in length, - * using a Pad1 or PadN option if necessary. */ -static int32_t -ext_align(uint8_t *buf, int32_t alloc, int32_t len) -{ - int32_t padlen = alloc - len; - buf += len; // Move to padding location - if (padlen == 1) { - buf[0] = 0; // Pad1 - } else if (padlen > 1) { - buf[0] = 1; // PadN - buf[1] = (uint8_t)(padlen - 2); - } else { - return -1; - } - return 0; -} - -/* Determines the compressed length (and some other parameters) from NHC_EXT - * compressed extension header */ -static int32_t -ext_compressed_length(uint8_t *buf, uint8_t eid, int32_t *compressed_len, int32_t *head) -{ - int32_t len = 0; - switch (eid) { - case EXT_HOPBYHOP: // Intentional fall-through - case EXT_ROUTING: // Intentional fall-through - case EXT_DSTOPT: // Intentional fall-through - if (!(buf[0] & NH_COMPRESSED)) { // [ DIS | NXT | LEN | ... (len) - len = 2 + buf[2]; - *compressed_len = len + 1; - } else { // [ DIS | LEN | ... (len) - len = 2 + buf[1]; - *compressed_len = len; - *head = 1; - } - return len; - case EXT_FRAG: // [ DIS | FRAG ... - len = 8; - *compressed_len = len; - return len; - default: // Something went wrong, bail out.. - return -1; - } -} - -/* Decompresses an extension header pointed to by 'f->net_hdr', according to the - * NHC_EXT compression scheme */ -static uint8_t * -decompressor_nhc_ext(struct pico_frame *f, int32_t *compressed_len, int32_t *decompressed_len) -{ - struct pico_ipv6_exthdr *ext = NULL; - int32_t len = 0, head = 0, alloc = 0; - uint8_t *buf = f->net_hdr; - uint8_t eid = buf[0] & 0x0E; - uint8_t nh = 0; - - if ((buf[0] & 0xF0) == EXT_DISPATCH) { - /* Determine compressed header length */ - len = ext_compressed_length(buf, eid, compressed_len, &head); - if (len >= 0) { - /* Retrieve next header from following header */ - nh = ext_nh_retrieve(buf, *compressed_len); - - /* Make sure options are 8 octet aligned */ - alloc = (len % 8) ? (((len / 8) + 1) * 8) : (len); - ext = (struct pico_ipv6_exthdr *)PICO_ZALLOC((size_t)alloc); - if (ext) { - buf_move((uint8_t *)ext + head, buf + 1, (size_t)(len - head)); - ext->nxthdr = nh; - if (EXT_HOPBYHOP == eid || EXT_DSTOPT == eid || EXT_ROUTING) { - ext->ext.destopt.len = (uint8_t)((alloc / 8) - 1); - ext_align((uint8_t *)ext, alloc, len); - } - } - *decompressed_len = alloc; - return (uint8_t *)ext; - } - } - return NULL; -} - -/* Free's memory of a all assembled chunks for 'n' amount */ -static struct pico_frame * -pico_iphc_bail_out(uint8_t **chunks, int32_t n) -{ - int32_t i = 0; - for (i = 0; i < n; i++) { - PICO_FREE(chunks[i]); - } - return NULL; -} - -/* Performs reassembly after either compression of decompression */ -static struct pico_frame * -pico_iphc_reassemble(struct pico_frame *f, uint8_t **chunks, int32_t *chunks_len, int32_t n, int32_t processed_len, int32_t handled_len) -{ - uint32_t grow = f->buffer_len; - struct pico_frame *new = NULL; - int32_t payload_len = 0; - uint8_t *dst = NULL; - int32_t ret = 0, i = 0; - - /* Calculate buffer size including IPv6 payload */ - payload_len = (int32_t)f->len - handled_len; - processed_len += payload_len; // Length of frame after processing - - /* Reallocate frame size if there isn't enough room available */ - if (f->len < (uint16_t)processed_len) { - grow = (uint32_t)(grow + (uint32_t)processed_len - f->len); - ret = pico_frame_grow(f, grow); - if (ret) - return pico_iphc_bail_out(chunks, n); - } - - chunks[n] = f->net_hdr + handled_len; // Start of payload_available - chunks_len[n] = payload_len; // Size of payload - n++; // Payload is another chunk to copy - - /* Provide a new frame */ - if (!(new = pico_frame_deepcopy(f))) - return pico_iphc_bail_out(chunks, n); - - /* Copy each chunk back in the frame starting at the end of the new - * frame-buffer so we don't overwrite overlapping memory regions */ - dst = new->buffer + new->buffer_len; - for (i = n - 1; i >= 0; i--) { - dst -= chunks_len[i]; - buf_move(dst, chunks[i], (size_t)chunks_len[i]); - } - new->net_hdr = dst; // Last destination is net_hdr - new->start = new->net_hdr; // Start of useful data is at net_hdr - new->len = (uint32_t)processed_len; - new->transport_len = 0; - new->payload_len = 0; - new->app_len = 0; - new->transport_hdr = new->net_hdr + new->net_len; - pico_iphc_bail_out(chunks, n - 1); // Success, discard compressed chunk - if (new->start < new->buffer) { - pico_frame_discard(new); - return NULL; - } - return new; -} - -/* Compresses a frame according to the IPHC, NHC_EXT and NHC_UDP compression scheme */ -static struct pico_frame * -pico_iphc_compress(struct pico_frame *f) -{ - int32_t i = 0, compressed_len = 0, loop = 1, uncompressed = f->net_len; - uint8_t *old_nethdr = f->net_hdr; // Save net_hdr temporary ... - uint8_t nh = PICO_PROTO_IPV6; - uint8_t *chunks[8] = { NULL }; - int32_t chunks_len[8] = { 0 }; - - do { - switch (nh) { - /* IPV6 HEADER */ - case PICO_PROTO_IPV6: - chunks[i] = compressor_iphc(f, &chunks_len[i], &nh); - f->net_hdr += 40; // Move after IPv6 header - f->net_len = (uint16_t)chunks_len[i]; - break; - /* IPV6 EXTENSION HEADERS */ - case PICO_IPV6_EXTHDR_HOPBYHOP: - case PICO_IPV6_EXTHDR_ROUTING: - case PICO_IPV6_EXTHDR_FRAG: - case PICO_IPV6_EXTHDR_DESTOPT: - chunks[i] = compressor_nhc_ext(f, &chunks_len[i], &nh); - f->net_len = (uint16_t)(f->net_len + chunks_len[i]); - /* f->net_hdr is updated in compresor_nhc_ext with original size */ - break; - /* UDP HEADER */ - case PICO_PROTO_UDP: - chunks[i] = compressor_nhc_udp(f, &chunks_len[i]); - uncompressed += PICO_UDPHDR_SIZE; - f->transport_len = (uint16_t)chunks_len[i]; - default: /* Intentional fall-through */ - loop = 0; - } - /* Check if an error occured */ - if (!chunks[i]) - return pico_iphc_bail_out(chunks, i); - /* Increment total compressed_len and increase iterator */ - compressed_len += chunks_len[i++]; - } while (compressible_nh(nh) && loop && i < 8); - - f->net_hdr = old_nethdr; // ... Restore old net_hdr - return pico_iphc_reassemble(f, chunks, chunks_len, i, compressed_len, uncompressed); -} - -/* Restore some IPv6 header fields like next header and payload length */ -static struct pico_frame * -pico_ipv6_finalize(struct pico_frame *f, uint8_t nh) -{ - struct pico_ipv6_hdr *hdr = NULL; - if (!f) { - return NULL; - } else { - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (!hdr->nxthdr) - hdr->nxthdr = nh; - hdr->len = short_be((uint16_t)(f->len - PICO_SIZE_IP6HDR)); - return f; - } -} - -/* Decompresses a frame according to the IPHC, NHC_EXT and NHC_UDP compression scheme */ -static struct pico_frame * -pico_iphc_decompress(struct pico_frame *f) -{ - int32_t i = 0, compressed = 0, loop = 1, uncompressed = 0, ret = 0; - uint8_t *old_nethdr = f->net_hdr; // Save net_hdr temporary ... - uint8_t dispatch = PICO_PROTO_IPV6; - uint8_t *chunks[8] = { NULL }; - struct pico_frame *n = NULL; - int32_t chunks_len[8] = { 0 }; - uint8_t nh = 0; - - do { - switch (dispatch) { - /* IPV6 HEADER */ - case PICO_PROTO_IPV6: - chunks[i] = decompressor_iphc(f, &ret); - chunks_len[i] = PICO_SIZE_IP6HDR; - f->net_len = PICO_SIZE_IP6HDR; - nh = ext_nh_retrieve(f->net_hdr, ret); - break; - /* IPV6 EXTENSION HEADERS */ - case PICO_IPV6_EXTHDR_HOPBYHOP: - case PICO_IPV6_EXTHDR_ROUTING: - case PICO_IPV6_EXTHDR_FRAG: - case PICO_IPV6_EXTHDR_DESTOPT: - chunks[i] = decompressor_nhc_ext(f, &ret, &chunks_len[i]); - f->net_len = (uint16_t)(f->net_len + chunks_len[i]); - break; - /* UDP HEADER */ - case PICO_PROTO_UDP: - f->transport_hdr = f->net_hdr; // Switch to transport header - chunks[i] = decompressor_nhc_udp(f, compressed, &ret); - chunks_len[i] = PICO_UDPHDR_SIZE; - default: /* Intentional fall-through */ - loop = 0; - } - /* Check if an error occured */ - if (!chunks[i]) - return pico_iphc_bail_out(chunks, i); - - /* Increase compressed and uncompressed length */ - compressed += ret; - uncompressed += chunks_len[i++]; - - /* Get next dispatch header */ - f->net_hdr += ret; - dispatch = ext_nh_retrieve(f->net_hdr, 0); - } while (dispatch && loop && i < 8); - f->net_hdr = old_nethdr; // ... Restore old net_hdr - - /* Reassemble gathererd decompressed buffers */ - n = pico_iphc_reassemble(f, chunks, chunks_len, i, uncompressed, compressed); - return pico_ipv6_finalize(n, nh); -} - -#endif - -/* Prepends an uncompressed IPv6 dispatch header */ -static void -pico_iphc_no_comp(struct pico_frame *f) -{ - f->net_hdr--; // Only need one bytes - f->start--; - f->len++; - f->net_len++; - f->net_hdr[0] = IPV6_DISPATCH; -} - -/* Removes an uncompressed IPv6 dispatch header */ -static void -pico_iphc_no_comp_dec(struct pico_frame *f) -{ - f->net_hdr++; - f->start++; - f->len--; - f->net_len--; -} - -/* Updates the fragmentation cookie with how many bytes there are copied and units - * of 8-octets that are transmitted, if bytes copied equals the size of the datagram - * the cookie is removed from the cookie-tree and the datagram is discarded */ -static int32_t -frag_update(struct pico_frame *f, struct frag_ctx *frag, uint8_t units, uint16_t copy) -{ - frag->dgram_off = (uint8_t)(frag->dgram_off + units); - frag->copied = (uint16_t)(frag->copied + copy); - /* Datagram is completely transmitted */ - if (frag->copied >= f->len) { - lp_dbg("6LP: FIN: "ORG"fragmentation"RST" with hash '%X', sent %u of %u bytes\n", frag->hash, frag->copied, f->len); - pico_tree_delete(&FragTree, frag); - PICO_FREE(frag); - pico_frame_discard(f); - } else { - lp_dbg("6LP: UPDATE: "ORG"fragmentation"RST" with hash '%X', sent %u of %u bytes\n", frag->hash, frag->copied, f->len); - return pico_datalink_send(f); - } - return (int32_t)1; // Success -} - -static void -frag_fill(uint8_t *frag, uint8_t dispatch, uint16_t dgram_size, uint16_t tag, uint8_t dgram_off, int32_t offset, uint16_t copy, uint16_t copied, uint8_t *buf) -{ - frag[0] = (uint8_t)(dispatch | ((uint8_t)short_be(dgram_size) & 0x07)); - frag[1] = (uint8_t)(short_be(dgram_size) >> 8); - frag[2] = (uint8_t)(short_be(tag)); - frag[3] = (uint8_t)(short_be(tag) >> 8); - frag[4] = (uint8_t)(dgram_off); - buf_move(frag + offset, buf + copied, copy); -} - -/* Looks for a fragmentation cookie and creates an n-th fragment frame that it - * tries to push to the datalink layer, if the entire datagram is transmitted, - * the fragment cookie is removed from the tree and the datagram is free'd */ -static int32_t -frag_nth(struct pico_frame *f) -{ - struct frag_ctx *frag = frag_ctx_find(f->hash); - uint16_t left = 0; - uint16_t copy = 0, alloc = FRAGN_SIZE; - struct pico_frame *n = NULL; - uint8_t units = 0; - int32_t avail = 0, ret = 0; - - if (frag) { - /* Check how many bytes there are available for n-th fragment */ - avail = pico_6lowpan_ll_push(f); - if (avail > 0) { - /* Calculate dgram_off and bytes to copy */ - left = (uint16_t)(f->len - frag->copied); - if (left <= (uint16_t)(avail - FRAGN_SIZE)) { - copy = left; - } else { - units = (uint8_t)((uint16_t)(avail - FRAGN_SIZE) >> 3); - copy = (uint16_t)(units << 3); - } - alloc = (uint16_t)(alloc + copy); - - n = pico_proto_6lowpan_ll.alloc(&pico_proto_6lowpan_ll, f->dev, alloc); - if (n) { - frag_fill(n->net_hdr, FRAGN_DISPATCH, frag->dgram_size, - frag->dgram_tag, frag->dgram_off, 5, copy, - frag->copied, f->net_hdr); - n->net_len = alloc; - n->len = (uint32_t)n->net_len; - n->src = frag->f->src; - n->dst = frag->f->dst; - - /* Try to push fragment to link layer */ - ret = pico_6lowpan_ll_push(n); - if (!ret) { // Update frag cookie - return frag_update(f, frag, units, copy); - } - } - } - } - - pico_frame_discard(f); - return -1; -} - -/* Makes a first fragment from a frame and tries to push it to the datalink layer - * Also enqueues the frame back in the outgoing frame-queue of the 6LOWPAN - * layer for subsequent fragments */ -static int32_t -frag_1st(struct pico_frame *f, uint16_t dgram_size, uint8_t dgram_off, uint16_t copy) -{ - uint16_t alloc = (uint16_t)(copy + FRAG1_SIZE); - struct pico_frame *n = NULL; - int32_t ret = 0; - - n = pico_proto_6lowpan_ll.alloc(&pico_proto_6lowpan_ll, f->dev, alloc); - if (n) { - frag_fill(n->net_hdr, FRAG1_DISPATCH, dgram_size, dgram_tag, 0, 4, copy, 0,f->net_hdr); - n->net_len = alloc; - n->len = (uint32_t)n->net_len; - n->src = f->src; - n->dst = f->dst; - - /* Try to push fragment to link layer */ - ret = pico_6lowpan_ll_push(n); - if (ret) { - dgram_tag--; - return -1; - } - - /* Enqueue the frame again for subsequent fragments */ - f->flags |= PICO_FRAME_FLAG_SLP_FRAG; - if (pico_datalink_send(f) <= 0) - return -1; - - /* Everything was a success store a cookie for subsequent fragments */ - return frag_store(f, dgram_size, dgram_tag++, dgram_off, copy, &FragTree); - } else { - pico_err = PICO_ERR_ENOMEM; - return -1; - } -} - -/* Send the first fragment of a uncompressed IPv6 datagram */ -static int32_t -frag_1st_no_comp(struct pico_frame *f, uint16_t dgram_size, int32_t available) -{ - /* Available bytes after inserting FRAG1 dispatch and IPv6 dispatch */ - uint16_t rest_size = (uint16_t)(available - FRAG1_SIZE - 1); - uint8_t dgram_off = (uint8_t)(rest_size >> 3); - uint16_t copy_size = (uint16_t)(rest_size + 1); - return frag_1st(f, dgram_size, dgram_off, copy_size); -} - -#ifdef PICO_6LOWPAN_IPHC_ENABLED -/* Determines the length of the compressed header */ -static uint16_t -frame_comp_hlen(struct pico_frame *f, int32_t udp) -{ - return (uint16_t)(f->net_len + ((udp) ? (f->transport_len) : (0))); -} - -/* Send the first fragment of a compressed datagram */ -static int32_t -frag_1st_comp(struct pico_frame *f, uint16_t dgram_size, int32_t available, int32_t udp) -{ - /* Calculate amount of bytes that are elided */ - uint16_t comp_diff = (uint16_t)(dgram_size - f->len); - uint16_t comp_hlen = frame_comp_hlen(f, udp); - /* Decompressed header length */ - uint16_t deco_hlen = (uint16_t)(comp_hlen + comp_diff); - /* Available octects after inserting FRAG1 dispatch and compressed header */ - uint16_t rest_size = (uint16_t)(available - FRAG1_SIZE - comp_hlen); - /* Offset for subsequent fragments in 8-octect units and in octets */ - uint8_t dgram_off = (uint8_t)((uint16_t)(rest_size + deco_hlen) >> 3); - uint16_t copy_size = 0; - /* 8-octet aligned available octets after decompression */ - rest_size = (uint16_t)((uint16_t)(dgram_off << 3) - deco_hlen); - copy_size = (uint16_t)(rest_size + comp_hlen); - return frag_1st(f, dgram_size, dgram_off, copy_size); -} -#endif - -static int32_t -pico_6lowpan_compress(struct pico_frame *f, int32_t avail) -{ - struct pico_ipv6_hdr *ip = (struct pico_ipv6_hdr *)f->net_hdr; - uint16_t dgram_size = (uint16_t)(short_be(ip->len) + PICO_SIZE_IP6HDR); - -#ifdef PICO_6LOWPAN_IPHC_ENABLED - int32_t udp = (PICO_PROTO_UDP == ip->nxthdr); - struct pico_frame *try = pico_iphc_compress(f); - if (try) { - /* Try to push frame to link layer */ - avail = pico_6lowpan_ll_push(try); - if (0 < avail && frame_comp_hlen(try, udp) <= (uint16_t)avail) { - /* RFC6282: any header that cannot fit within the first fragment - * MUST NOT be compressed. */ - pico_frame_discard(f); - return frag_1st_comp(try, dgram_size, avail, udp); - } else if (!avail) { - pico_frame_discard(f); - return (int32_t)try->len; // Success, compression was enough - } else if (0 > avail) { - pico_frame_discard(try); - pico_frame_discard(f); - return -1; // Error pushing compressed frame - } - pico_frame_discard(try); - } -#endif - - pico_iphc_no_comp(f); // Add uncompressed dispatch header again - return frag_1st_no_comp(f, dgram_size, avail); -} - -/* General compression function that first tries to compress the frame and sends - * it through to the link layer, if that doesn't work the frame is fragmented */ -static int32_t -pico_6lowpan_send(struct pico_frame *f) -{ - int32_t avail = 0; - pico_iphc_no_comp(f); // Add uncrompressed dispatch header ... - - /* Try to push frame to link layer */ - avail = pico_6lowpan_ll_push(f); - if (avail > 0) { - pico_iphc_no_comp_dec(f); // ... remove IPv6 Dispatch Header - return pico_6lowpan_compress(f, avail); - } else if (!avail) { // Success - return (int32_t)f->len; - } else { - return -1; - } -} - -static int32_t -pico_6lowpan_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - - /* Check if it's meant for fragmentation */ - if (f->flags & PICO_FRAME_FLAG_SLP_FRAG) { - return frag_nth(f); - } else if ((f->net_hdr[0] & 0xF0) != 0x60) { - lp_dbg("6lowpan - ERROR: not an IPv6 frame\n"); - goto fin; - } else if (!f->dev || LL_MODE_ETHERNET == f->dev->mode) { - lp_dbg("6lowpan - ERROR: link layer mode not supported\n"); - goto fin; - } - - lp_dbg("6LP: ***NEW***, some stats: "); - lp_dbg("len: %d net_len: %d transport_len: %d\n", f->len, f->net_len, f->transport_len); - - /* Retrieve link layer addresses */ - if (pico_6lowpan_lls[f->dev->mode].addr_from_net(&f->src, f, 0) || - pico_6lowpan_lls[f->dev->mode].addr_from_net(&f->dst, f, 1)) { - /* Address mode is unspecified, probably destination ll-address is being resolved */ - return (int32_t)f->len; - } - - return pico_6lowpan_send(f); -fin: - pico_frame_discard(f); - return -1; -} - -static struct pico_frame * -pico_6lowpan_decompress(struct pico_frame *f) -{ -#ifdef PICO_6LOWPAN_IPHC_ENABLED - struct pico_frame *dec = NULL; -#endif - - if (0) {} -#ifdef PICO_6LOWPAN_IPHC_ENABLED - else if ((f->net_hdr[0] & 0xE0) == IPHC_DISPATCH) { - dec = pico_iphc_decompress(f); - pico_frame_discard(f); - return dec; - } -#endif - else if (f->net_hdr[0] == IPV6_DISPATCH) { - pico_iphc_no_comp_dec(f); - return f; - } else { - lp_dbg("6LP: RCVD invalid frame\n"); - pico_frame_discard(f); - return NULL; - } -} - -static int32_t -defrag_new(struct pico_frame *f, uint16_t dgram_size, uint16_t tag, uint16_t off) -{ - struct pico_frame *r = pico_proto_6lowpan_ll.alloc(&pico_proto_6lowpan_ll, f->dev, dgram_size); - if (r) { - r->start = r->buffer + (int32_t)(r->buffer_len - (uint32_t)dgram_size); - r->len = dgram_size; - r->net_hdr = r->start; - r->net_len = f->net_len; - r->transport_len = (uint16_t)(r->len - r->net_len); - r->src = f->src; - r->dst = f->dst; - buf_move(r->net_hdr + off, f->start, f->len); - if (frag_store(r, dgram_size, tag, 0, (uint16_t)f->len, &ReassemblyTree) < 0) { - pico_frame_discard(f); - pico_frame_discard(r); - return -1; - } - } - pico_frame_discard(f); - return 1; -} - -static int32_t -defrag_update(struct frag_ctx *frag, uint16_t off, struct pico_frame *f) -{ - struct pico_frame *r = frag->f; - buf_move(r->start + (int32_t)off, f->start, f->len); // Copy at start - frag->copied = (uint16_t)(frag->copied + (uint16_t)f->len); - pico_frame_discard(f); - if (frag->copied >= frag->dgram_size) { // Datagram completely reassembled - lp_dbg("6LP: FIN: "GRN"reassembly"RST" with tag '%u', stats: len: %d net: %d trans: %d\n", frag->dgram_tag, r->len, r->net_len, r->transport_len); - pico_tree_delete(&ReassemblyTree, frag); - PICO_FREE(frag); -#ifdef PICO_6LOWPAN_IPHC_ENABLED - r = pico_ipv6_finalize(r, 0); -#endif - return pico_network_receive(r); - } else { - lp_dbg("6LP: UPDATE: "GRN"reassembly"RST" with tag '%u', %u of %u bytes received\n", frag->dgram_tag, frag->copied, frag->dgram_size); - } - return (int32_t)r->len; -} - -static struct frag_ctx * -defrag_remove_header(struct pico_frame *f, uint16_t *dgram_size, uint16_t *tag, uint16_t *off, int32_t size) -{ - *dgram_size = (uint16_t)(((uint16_t)(f->net_hdr[0] & 0x07) << 8) | (uint16_t)f->net_hdr[1]); - *tag = (uint16_t)(((uint16_t)f->net_hdr[2] << 8) | (uint16_t)f->net_hdr[3]); - *off = (uint16_t)((uint16_t)f->net_hdr[4] << 3); - f->net_len = (uint16_t)(f->net_len - (uint16_t)size); - f->len = (uint32_t)(f->len - (uint32_t)size); - f->net_hdr += size; - f->start = f->net_hdr; - return frag_find(*dgram_size, *tag, f); -} - -static int32_t -defrag(struct pico_frame *f) -{ - uint16_t size = 0, tag = 0, off = 0; - struct frag_ctx *frag = NULL; - - if ((f->net_hdr[0] & 0xF8) == FRAG1_DISPATCH) { - frag = defrag_remove_header(f, &size, &tag, &off, FRAG1_SIZE); - if (!(f = pico_6lowpan_decompress(f))) - return -1; - off = 0; - } else if ((f->net_hdr[0] & 0xF8) == FRAGN_DISPATCH) { - frag = defrag_remove_header(f, &size, &tag, &off, FRAGN_SIZE); - } else { - lp_dbg("6LP: RCVD invalid frame\n"); - pico_frame_discard(f); - return -1; - } - - if (frag) { - return defrag_update(frag, off, f); - } else { - return defrag_new(f, size, tag, off); - } -} - -static int32_t -pico_6lowpan_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - - if (f->net_hdr[0] & 0x80) { - return defrag(f); - } else { - f = pico_6lowpan_decompress(f); - if (f) { - lp_dbg("6LP: Decompression finished, stats: len: %d net: %d trans: %d\n", f->len, f->net_len, f->transport_len); - return pico_network_receive(f); - } - return -1; - } -} - -int32_t -pico_6lowpan_pull(struct pico_frame *f) -{ - if (pico_enqueue(pico_proto_6lowpan.q_in, f) > 0) { - return (int32_t)f->len; // Success - } - - pico_frame_discard(f); - return -1; -} - -struct pico_protocol pico_proto_6lowpan = { - .name = "6lowpan", - .layer = PICO_LAYER_DATALINK, - .process_in = pico_6lowpan_process_in, - .process_out = pico_6lowpan_process_out, - .q_in = &pico_6lowpan_in, - .q_out = &pico_6lowpan_out -}; - -int pico_6lowpan_init(void) -{ - pico_6lowpan_ll_init(); - if (0 == pico_timer_add(1000, frag_timeout, NULL)) { - return -1; /* We care if timer fails, results in memory leak if frames don't get reassembled */ - } - return 0; -} - -#endif /* PICO_SUPPORT_6LOWPAN */ diff --git a/ext/picotcp/modules/pico_6lowpan.h b/ext/picotcp/modules/pico_6lowpan.h deleted file mode 100644 index c54e03f..0000000 --- a/ext/picotcp/modules/pico_6lowpan.h +++ /dev/null @@ -1,40 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights - reserved. See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -#ifndef INCLUDE_PICO_6LOWPAN -#define INCLUDE_PICO_6LOWPAN - -#include "pico_protocol.h" -#include "pico_device.h" -#include "pico_config.h" -#include "pico_frame.h" - -#define PICO_6LP_FLAG_LOWPAN (0x01) -#define PICO_6LP_FLAG_NOMAC (0x02) - -#ifdef PICO_SUPPORT_6LOWPAN -#define PICO_DEV_IS_6LOWPAN(dev) ((dev) && ((dev)->hostvars.lowpan_flags & PICO_6LP_FLAG_LOWPAN)) -#define PICO_DEV_IS_NOMAC(dev) ((dev) && ((dev)->hostvars.lowpan_flags & PICO_6LP_FLAG_NOMAC)) -#else -#define PICO_DEV_IS_6LOWPAN(dev) (0) -#define PICO_DEV_IS_NOMAC(dev) (0) -#endif - -/****************************************************************************** - * Public variables - ******************************************************************************/ - -extern struct pico_protocol pico_proto_6lowpan; - -/****************************************************************************** - * Public functions - ******************************************************************************/ - -int32_t pico_6lowpan_pull(struct pico_frame *f); -int pico_6lowpan_init(void); - -#endif /* INCLUDE_PICO_6LOWPAN */ diff --git a/ext/picotcp/modules/pico_6lowpan_ll.c b/ext/picotcp/modules/pico_6lowpan_ll.c deleted file mode 100644 index b099c1f..0000000 --- a/ext/picotcp/modules/pico_6lowpan_ll.c +++ /dev/null @@ -1,454 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -#include "pico_ipv6.h" -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_802154.h" -#include "pico_6lowpan.h" -#include "pico_protocol.h" -#include "pico_addressing.h" -#include "pico_6lowpan_ll.h" - -#ifdef PICO_SUPPORT_6LOWPAN - -/******************************************************************************* - * Macros - ******************************************************************************/ - -#ifdef DEBUG_6LOWPAN -#define ll_dbg dbg -#else -#define ll_dbg(...) do {} while(0) -#endif - -/******************************************************************************* - * Constants - ******************************************************************************/ - -/* Lifetime check interval */ -#define ONE_MINUTE ((pico_time)(1000 * 60)) - -/* Number of extensions */ -#define NUM_LL_EXTENSIONS (2) - -/******************************************************************************* - * Type definitions - ******************************************************************************/ - -struct extension { - int32_t (*estimate)(struct pico_frame *f); - int32_t (*out)(struct pico_frame *f); - int32_t (*in)(struct pico_frame *f); -}; - -/******************************************************************************* - * Global Variables - ******************************************************************************/ - -static const struct pico_6lowpan_ll_protocol pico_6lowpan_ll_none = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -/* Declare a global lookup-table for distribution of link layer specific tasks */ -struct pico_6lowpan_ll_protocol pico_6lowpan_lls[PICO_6LOWPAN_LLS + 1]; - -static struct pico_queue pico_6lowpan_ll_in = { - 0 -}; -static struct pico_queue pico_6lowpan_ll_out = { - 0 -}; - -/******************************************************************************* - * CTX - ******************************************************************************/ - -#ifdef PICO_6LOWPAN_IPHC_ENABLED - -/* Compares if the IPv6 prefix of two IPv6 addresses match */ -static int32_t compare_prefix(uint8_t *a, uint8_t *b, int32_t len) -{ - uint8_t bitmask = (uint8_t)(0xff << (8 - (len % 8))); - size_t bytes = (size_t)len / 8; - int32_t ret = 0; - if ((ret = memcmp(a, b, bytes))) - return ret; - return (int32_t)((a[bytes] & bitmask) - (b[bytes] & bitmask)); -} - -/* Compares 2 IPHC context entries */ -static int32_t compare_ctx(void *a, void *b) -{ - struct iphc_ctx *ca = (struct iphc_ctx *)a; - struct iphc_ctx *cb = (struct iphc_ctx *)b; - return compare_prefix(ca->prefix.addr, cb->prefix.addr, ca->size); -} - -PICO_TREE_DECLARE(CTXtree, compare_ctx); - -/* Searches in the context tree if there's a context entry available with the - * prefix of the IPv6 address */ -struct iphc_ctx * ctx_lookup(struct pico_ip6 addr) -{ - struct iphc_ctx test = { NULL, addr, 0, 0, 0, 0 }; - return pico_tree_findKey(&CTXtree, &test); -} - -/* Looks up the context by ID, for decompression */ -struct iphc_ctx * ctx_lookup_id(uint8_t id) -{ - struct iphc_ctx *key = NULL; - struct pico_tree_node *i = NULL; - - pico_tree_foreach(i, &CTXtree) { - key = i->keyValue; - if (key && id ==key->id) - return key; - } - return NULL; -} - -/* Tries to insert a new IPHC-context into the Context-tree */ -static int32_t ctx_insert(struct pico_ip6 addr, uint8_t id, uint8_t size, pico_time lifetime, uint8_t flags, struct pico_device *dev) -{ - struct iphc_ctx *new = PICO_ZALLOC(sizeof(struct iphc_ctx)); - if (new) { - new->lifetime = lifetime; - new->prefix = addr; - new->flags = flags; - new->size = size; - new->dev = dev; - new->id = id; - if (pico_tree_insert(&CTXtree, new)) { - PICO_FREE(new); - return -1; - } - } else { - return -1; - } - return 0; -} - -/* Function to update context table from 6LoWPAN Neighbor Discovery */ -void ctx_update(struct pico_ip6 addr, uint8_t id, uint8_t size, pico_time lifetime, uint8_t flags, struct pico_device *dev) -{ - struct iphc_ctx *entry = ctx_lookup_id(id); - if (entry && dev == entry->dev) { - if (!lifetime) { - pico_tree_delete(&CTXtree, entry); - PICO_FREE(entry); - return; - } - entry->prefix = addr; - entry->size = size; - entry->lifetime = lifetime; - entry->flags = flags; - } else { - /* We don't care if it failed */ - (void)ctx_insert(addr, id, size, lifetime, flags, dev); - } -} - -/* Check whether or not particular contexts are expired and remove them if so. Contexts - * are reconfirmed before their lifetime expires */ -static void ctx_lifetime_check(pico_time now, void *arg) -{ - struct pico_tree_node *i = NULL, *next = NULL; - struct pico_ipv6_route *gw = NULL; - struct iphc_ctx *key = NULL; - IGNORE_PARAMETER(now); - IGNORE_PARAMETER(arg); - - pico_tree_foreach_safe(i, &CTXtree, next) { - if (i && i->keyValue) { - key = i->keyValue; - key->lifetime--; - if (!key->lifetime) { - pico_tree_delete(&CTXtree, key); - PICO_FREE(key); - } else if (key->lifetime == 5) { - /* RFC6775: The host SHOULD unicast one or more RSs to the router well before the - * shortest of the, Router Lifetime, PIO lifetimes and the lifetime of the 6COs. */ - gw = pico_ipv6_gateway_by_dev(key->dev); - while (gw) { - pico_6lp_nd_start_soliciting(pico_ipv6_linklocal_get(key->dev), gw); - gw = pico_ipv6_gateway_by_dev_next(key->dev, gw); - } - } - } - } - - (void)pico_timer_add(ONE_MINUTE, ctx_lifetime_check, NULL); -} - -#endif - -/******************************************************************************* - * MESH-UNDER ROUTING LAYER - ******************************************************************************/ - -/* XXX: Extensible processing function for outgoing frames. Here, the mesh header - * for a Mesh-Under topology can be prepended and the link layer source and - * destination addresses can be updated */ -static int32_t -ll_mesh_header_process_in(struct pico_frame *f) -{ - IGNORE_PARAMETER(f); - return 0; -} - -/* XXX: Extensible processing function for outgoing frames. Here, the mesh header - * for a Mesh-Under topology can be prepended and the link layer source and - * destination addresses can be updated */ -static int32_t -ll_mesh_header_process_out(struct pico_frame *f) -{ - IGNORE_PARAMETER(f); - return 0; -} - -/* XXX: Extensible function that estimates the size of the mesh header to be - * prepended based on the frame, the source and destination link layer address */ -static int32_t -ll_mesh_header_estimator(struct pico_frame *f) -{ - IGNORE_PARAMETER(f); - return 0; -} - -/******************************************************************************* - * GENERIC 6LOWPAN LINK LAYER - ******************************************************************************/ - -static int32_t -ll_mac_header_process_in(struct pico_frame *f) -{ - if (f && f->dev && pico_6lowpan_lls[f->dev->mode].process_in) { - return (int32_t)pico_6lowpan_lls[f->dev->mode].process_in(f); - } else { - return -1; - } -} - -static int32_t -ll_mac_header_process_out(struct pico_frame *f) -{ - if (f && f->dev && pico_6lowpan_lls[f->dev->mode].process_out) { - return (int32_t)pico_6lowpan_lls[f->dev->mode].process_out(f); - } else { - return -1; - } -} - -static int32_t -ll_mac_header_estimator(struct pico_frame *f) -{ - if (f && f->dev && pico_6lowpan_lls[f->dev->mode].estimate) { - return (int32_t)pico_6lowpan_lls[f->dev->mode].estimate(f); - } else { - return -1; - } -} - -/* Alloc's a frame with device's overhead and maximum IEEE802.15.4 header size */ -static struct pico_frame * -pico_6lowpan_frame_alloc(struct pico_protocol *self, struct pico_device *dev, uint16_t size) -{ - IGNORE_PARAMETER(self); - if (dev && pico_6lowpan_lls[dev->mode].alloc) { - return pico_6lowpan_lls[dev->mode].alloc(dev, size); - } else { - return NULL; - } -} - -/******************************************************************************* - * 6LOWPAN LINK LAYER PROTOCOL - ******************************************************************************/ - -const struct extension exts[] = { - {ll_mesh_header_estimator, ll_mesh_header_process_out, ll_mesh_header_process_in}, - {ll_mac_header_estimator, ll_mac_header_process_out, ll_mac_header_process_in}, -}; - -static int32_t -pico_6lowpan_ll_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - uint32_t datalink_len = 0; - int32_t ret = 0, i = 0; - IGNORE_PARAMETER(self); - - /* Every link layer extension updates the datalink pointer of the frame a little bit. */ - f->datalink_hdr = f->net_hdr; - - /* Call each of the outgoing processing functions */ - for (i = 0; i < NUM_LL_EXTENSIONS; i++) { - ret = exts[i].out(f); - if (ret < 0) /* Processing failed, no way to recover, discard frame */ - goto fin; - datalink_len = (uint32_t)(datalink_len + (uint32_t)ret); - if ((f->net_hdr - datalink_len) < f->buffer) /* Before buffer bound check */ - goto fin; - } - - /* Frame is ready for sending to the device driver */ - f->start = f->datalink_hdr; - f->len = (uint32_t)(f->len + datalink_len); - return (int32_t)(pico_sendto_dev(f) <= 0); -fin: - pico_frame_discard(f); - return -1; -} - -static int32_t -pico_6lowpan_ll_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - int32_t i = 0, ret = 0; - uint32_t len = 0; - IGNORE_PARAMETER(self); - - /* net_hdr is the pointer that is dynamically updated by the incoming - * processing functions to always point to right after a particular - * header, whether it's MAC, MESH, LL_SEC, ... eventually net_hdr will - * point to 6LoWPAN header which is exactly what we want */ - f->net_hdr = f->buffer; - - for (i = NUM_LL_EXTENSIONS - 1; i >= 0; i--) { - ret = exts[i].in(f); - switch (ret) { - case FRAME_6LOWPAN_LL_RELEASE: - /* Success, frame is somewhere else now.. */ - break; - case FRAME_6LOWPAN_LL_DISCARD: - /* Something went wrong, discard the frame */ - pico_frame_discard(f); - break; - default: - /* Success, update link layer header length */ - len = (uint32_t)(len + (uint32_t)ret); - } - } - - /* Determine size at network layer */ - f->net_len = (uint16_t)(f->len - len); - f->len = (uint32_t)(f->len - len); - return pico_6lowpan_pull(f); -} - -/* Entry point for incoming 6LoWPAN frames, proxy for pico_stack_recv. This allows passing the link - * layer source and destination address as well */ -int32_t pico_6lowpan_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len, union pico_ll_addr *src, union pico_ll_addr *dst) -{ - int32_t ret = 0; - ll_dbg("6LoWPAN - Stack recv called!\n"); - if (PICO_DEV_IS_NOMAC(dev)) { - struct pico_frame *f = pico_stack_recv_new_frame(dev, buffer, len); - if (f) { - f->src = *src; - f->dst = *dst; - ret = pico_enqueue(dev->q_in, f); - if (0 >= ret) - pico_frame_discard(f); - return ret; - } - } else { - return pico_stack_recv(dev, buffer, len); - } - return -1; // return ERROR -} - -/* Proxy for pico_devloop_sendto_dev, 6LoWPAN-devices have a different interface with pico. This - * allows passing the link layer source and destination address as well */ -int32_t pico_6lowpan_ll_sendto_dev(struct pico_device *dev, struct pico_frame *f) -{ - /* FINAL OUTGOING POINT OF 6LOWPAN STACK */ - return ((struct pico_dev_6lowpan *)dev)->send(dev, f->start, (int32_t)f->len, f->src, f->dst); -} - -/* Initialisation routine for 6LoWPAN specific devices */ -int pico_dev_6lowpan_init(struct pico_dev_6lowpan *dev, const char *name, uint8_t *mac, enum pico_ll_mode ll_mode, uint16_t mtu, uint8_t nomac, - int (* send)(struct pico_device *dev, void *_buf, int len, union pico_ll_addr src, union pico_ll_addr dst), - int (* poll)(struct pico_device *dev, int loop_score)) -{ - struct pico_device *picodev = (struct pico_device *)dev; - if (!dev || !send || !poll) { - return -1; - } - - picodev->mode = ll_mode; - picodev->hostvars.lowpan_flags = PICO_6LP_FLAG_LOWPAN; - if (nomac) { - picodev->hostvars.lowpan_flags |= PICO_6LP_FLAG_NOMAC; - } - picodev->mtu = mtu; - picodev->poll = poll; - picodev->send = NULL; - dev->send = send; - - return pico_device_init(picodev, name, mac); -} - - -/* Push function for 6LoWPAN to call when it wants to try to send te frame to the device-driver */ -int32_t -pico_6lowpan_ll_push(struct pico_frame *f) -{ - uint16_t frame_size, pl_available = 0; - int32_t i = 0; - - if (!f || !f->dev) - return -1; - frame_size = (uint16_t)(f->len); - - /* Restrict frames to be as large as the device's MTU. */ - pl_available = (uint16_t)f->dev->mtu; - - /* Call each of the estimator functions of the additional headers to - * determine if the frame fits inside a single 802.15.4 frame, if it doesn't - * in the end, return the available bytes */ - for (i = 0; i < NUM_LL_EXTENSIONS; i++) { - pl_available = (uint16_t)(pl_available - exts[i].estimate(f)); - } - if (frame_size > pl_available) - return pl_available; - - /* Make sure these addresses are retrievable from the frame on processing */ - if (pico_enqueue(pico_proto_6lowpan_ll.q_out,f) > 0) { - return 0; // Frame enqueued for later processing - } - return -1; // Return ERROR -} - -struct pico_protocol pico_proto_6lowpan_ll = { - .name = "6lowpan_ll", - .layer = PICO_LAYER_DATALINK, - .alloc = pico_6lowpan_frame_alloc, - .process_in = pico_6lowpan_ll_process_in, - .process_out = pico_6lowpan_ll_process_out, - .q_in = &pico_6lowpan_ll_in, - .q_out = &pico_6lowpan_ll_out -}; - -void pico_6lowpan_ll_init(void) -{ - int32_t i = 0; - -#ifdef PICO_6LOWPAN_IPHC_ENABLED - /* We don't care about failure */ - (void)pico_timer_add(60000, ctx_lifetime_check, NULL); -#endif - - /* Initialize interface with 6LoWPAN link layer protocols */ - pico_6lowpan_lls[i++] = pico_6lowpan_ll_none; - -#ifdef PICO_SUPPORT_802154 - pico_6lowpan_lls[i++] = pico_6lowpan_ll_802154; -#endif -} - -#endif /* PICO_SUPPORT_6LOWPAN */ diff --git a/ext/picotcp/modules/pico_6lowpan_ll.h b/ext/picotcp/modules/pico_6lowpan_ll.h deleted file mode 100644 index 06cde23..0000000 --- a/ext/picotcp/modules/pico_6lowpan_ll.h +++ /dev/null @@ -1,122 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights - reserved. See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -#ifndef INCLUDE_PICO_6LOWPAN_LL -#define INCLUDE_PICO_6LOWPAN_LL - -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_6lowpan.h" -#include "pico_device.h" -#include "pico_config.h" -#include "pico_frame.h" -#include "pico_ipv6.h" - -/* Possible actions to perform on a received frame */ -#define FRAME_6LOWPAN_LL_RELEASE (-1) -#define FRAME_6LOWPAN_LL_DISCARD (-2) - -/******************************************************************************* - * CTX - ******************************************************************************/ - -#ifdef PICO_6LOWPAN_IPHC_ENABLED - -#define PICO_IPHC_CTX_COMPRESS (0x01u) - -struct iphc_ctx -{ - struct pico_device *dev; - struct pico_ip6 prefix; - uint8_t id; - uint8_t size; - uint8_t flags; - pico_time lifetime; -}; - -/* - * Looks up a context entry for a particular IPv6-address contained in 'addr' and returns it. - * Returns NULL if no entry is found. (See RFC4944) - */ -struct iphc_ctx * ctx_lookup(struct pico_ip6 addr); - -/* - * Looks up a context entry that belongs to a certain context identifier. - * Returns NULL if no belonging entry is found. (See RFC4944) - */ -struct iphc_ctx * ctx_lookup_id(uint8_t id); - -/* - * Creates a new, or updates and existing, context entry for a certain IPv6 address. (See RFC4944) - */ -void ctx_update(struct pico_ip6 addr, uint8_t id, uint8_t size, pico_time lifetime, uint8_t flags, struct pico_device *dev); - -#endif - -/****************************************************************************** - * Interface with device drivers - ******************************************************************************/ - -struct pico_dev_6lowpan -{ - /* Interface with picoTCP */ - struct pico_device dev; - - /* Transmit-function: - * - * @param dev The device who's send-function got called - * @param _buf Buffer containing the frame to be send over the network - * @param len Length of _buf - * @param src Link Layer source address of the device (IETF-endianness) - * @param dst Link layer destination address of the device (IETF-endianness) - * - * @return length of the frame that is transmitted on success, -1 on failure - */ - int (* send)(struct pico_device *dev, void *_buf, int len, union pico_ll_addr src, union pico_ll_addr dst); -}; - -/* Initialisation routine for 6LoWPAN specific devices */ -int pico_dev_6lowpan_init(struct pico_dev_6lowpan *dev, const char *name, uint8_t *mac, enum pico_ll_mode ll_mode, uint16_t mtu, uint8_t nomac, - int (* send)(struct pico_device *dev, void *_buf, int len, union pico_ll_addr src, union pico_ll_addr dst), - int (* poll)(struct pico_device *dev, int loop_score)); - -/****************************************************************************** - * Interface with link layer - ******************************************************************************/ - -struct pico_6lowpan_ll_protocol -{ - int32_t (* process_in)(struct pico_frame *f); - int32_t (* process_out)(struct pico_frame *f); - int32_t (* estimate)(struct pico_frame *f); - int32_t (* addr_from_buf)(union pico_ll_addr *addr, uint8_t *buf); - int32_t (* addr_from_net)(union pico_ll_addr *addr, struct pico_frame *f, int32_t dest); - int32_t (* addr_len)(union pico_ll_addr *addr); - int32_t (* addr_cmp)(union pico_ll_addr *a, union pico_ll_addr *b); - int32_t (* addr_iid)(uint8_t *iid, union pico_ll_addr *addr); - struct pico_frame * (*alloc)(struct pico_device *dev, uint16_t size); -}; - -/****************************************************************************** - * Public variables - ******************************************************************************/ - -extern struct pico_6lowpan_ll_protocol pico_6lowpan_lls[]; -extern struct pico_protocol pico_proto_6lowpan_ll; - -/****************************************************************************** - * Public functions - ******************************************************************************/ - -void pico_6lowpan_ll_init(void); -int32_t pico_6lowpan_ll_push(struct pico_frame *f); -int32_t pico_6lowpan_ll_pull(struct pico_frame *f); -int32_t frame_6lowpan_ll_store_addr(struct pico_frame *f); -int32_t pico_6lowpan_ll_sendto_dev(struct pico_device *dev, struct pico_frame *f); -int32_t pico_6lowpan_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len, union pico_ll_addr *src, union pico_ll_addr *dst); - -#endif /* INCLUDE_PICO_6LOWPAN_LL */ diff --git a/ext/picotcp/modules/pico_802154.c b/ext/picotcp/modules/pico_802154.c deleted file mode 100644 index 3647059..0000000 --- a/ext/picotcp/modules/pico_802154.c +++ /dev/null @@ -1,456 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights - reserved. See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_802154.h" -#include "pico_6lowpan.h" -#include "pico_protocol.h" -#include "pico_addressing.h" -#include "pico_6lowpan_ll.h" - -#ifdef PICO_SUPPORT_802154 - -/******************************************************************************* - * Macros - ******************************************************************************/ - -#define PICO_802154_VALID(am) ((am) == 2 || (am) == 3 ? 1 : 0) - -/******************************************************************************* - * Constants - ******************************************************************************/ - -/* Frame type definitions */ -#define FCF_TYPE_BEACON (short_be(0x0000u)) -#define FCF_TYPE_DATA (short_be(0x0001u)) -#define FCF_TYPE_ACK (short_be(0x0002u)) -#define FCF_TYPE_CMD (short_be(0x0003u)) - -/* Frame version definitions */ -#define FCF_VER_2003 (short_be(0x0000u)) -#define FCF_VER_2006 (short_be(0x1000u)) -#define FCF_SEC (short_be(0x0008u)) -#define FCF_NO_SEC (short_be(0x0000u)) -#define FCF_PENDING (short_be(0x0010u)) -#define FCF_NO_PENDING (short_be(0x0000u)) -#define FCF_ACK_REQ (short_be(0x0020u)) -#define FCF_NO_ACK_REQ (short_be(0x0000u)) -#define FCF_INTRA_PAN (short_be(0x0040u)) -#define FCF_INTER_PAN (short_be(0x0000u)) - -/* Commonly used addresses */ -#define ADDR_802154_BCAST (short_be(0xFFFFu)) -#define ADDR_802154_UNSPEC (short_be(0xFFFEu)) - -#ifndef PICO_6LOWPAN_NOMAC - -/******************************************************************************* - * ENDIANNESS - ******************************************************************************/ - -/* Swaps the two 8-bit values, the pointer A and B point at */ -static void pico_swap(uint8_t *a, uint8_t *b) -{ - *a = *a ^ *b; - *b = *a ^ *b; - *a = *a ^ *b; -} - -/* Converts an IEEE802.15.4 address, which is little endian by standard, to - * IETF-endianness, which is big endian. */ -static void -addr_802154_to_ietf(struct pico_802154 *addr) -{ - int32_t i = 0; - int32_t end = SIZE_6LOWPAN(addr->mode) - 1; - for (i = 0; i < (int32_t)((uint8_t)SIZE_6LOWPAN(addr->mode) >> 1); i++) { - pico_swap(&addr->addr.data[i], &addr->addr.data[end - i]); - } -} - -/* Converts an IEE802.15.4 address in IETF format, which is used to form the IID - * of the host's IPv6 addresses, back to IEEE-endianess, which is little - * endian. */ -static void -addr_802154_to_ieee(struct pico_802154 *addr) -{ - addr_802154_to_ietf(addr); -} - -/******************************************************************************* - * FRAME - ******************************************************************************/ - -/* Retrieves the addressing mode of the destination address from the MHR's frame - * control field. */ -static uint8_t -dst_am(struct pico_802154_hdr *hdr) -{ - return (uint8_t)((hdr->fcf >> 10) & 0x3); -} - -/* Retrieves the addressing mode of the source address from the MHR's frame - * control field */ -static uint8_t -src_am(struct pico_802154_hdr *hdr) -{ - return (uint8_t)((hdr->fcf >> 14) & 0x3); -} - -/* Determines the size of an IEEE802.15.4-header, based on the addressing - * modes */ -static uint8_t -frame_802154_hdr_len(struct pico_802154_hdr *hdr) -{ - return (uint8_t)(SIZE_802154_MHR_MIN + SIZE_6LOWPAN(src_am(hdr)) + SIZE_6LOWPAN(dst_am(hdr))); -} - -/* Gets the source address out of a mapped IEEE802.15.4-frame, converts it - * to host endianess */ -static struct pico_802154 -frame_802154_src(struct pico_802154_hdr *hdr) -{ - struct pico_802154 src = { .addr.data = { 0 }, .mode = src_am(hdr) }; - uint8_t *addresses = (uint8_t *)hdr + sizeof(struct pico_802154_hdr); - uint16_t len = SIZE_6LOWPAN(src.mode); - memcpy(src.addr.data, addresses + SIZE_6LOWPAN(dst_am(hdr)), len); - addr_802154_to_ietf(&src); - return src; -} - -/* Gets the destination address out of a mapped IEEE802.15.4-frame, converts - * it to host endianess */ -static struct pico_802154 -frame_802154_dst(struct pico_802154_hdr *hdr) -{ - struct pico_802154 dst = { .addr.data = { 0 }, .mode = dst_am(hdr) }; - uint8_t *addresses = (uint8_t *)hdr + sizeof(struct pico_802154_hdr); - uint16_t len = SIZE_6LOWPAN(dst.mode); - memcpy(dst.addr.data, addresses, len); - addr_802154_to_ietf(&dst); - return dst; -} - -/* Maps a 802.15.4 frame structure onto a flat buffer, fills in the entire - * header and set the payload pointer right after the MHR. */ -static void -frame_802154_format(uint8_t *buf, uint8_t seq, uint16_t intra_pan, uint16_t ack, - uint16_t sec, struct pico_6lowpan_short pan, struct pico_802154 src, - struct pico_802154 dst) -{ - uint8_t *addresses = (uint8_t *)(buf + sizeof(struct pico_802154_hdr)); - struct pico_802154_hdr *hdr = (struct pico_802154_hdr *)buf; - uint16_t sam = 0, dam = 0; - - hdr->fcf = 0; /* Clear out control field */ - intra_pan = (uint16_t)(intra_pan & FCF_INTRA_PAN); - ack = (uint16_t)(ack & FCF_ACK_REQ); - sec = (uint16_t)(sec & FCF_SEC); - dam = short_be((uint16_t)(dst.mode << 10)); - sam = short_be((uint16_t)(src.mode << 14)); - - /* Fill in frame control field */ - hdr->fcf |= (uint16_t)(FCF_TYPE_DATA | sec ); - hdr->fcf |= (uint16_t)(FCF_NO_PENDING | ack); - hdr->fcf |= (uint16_t)(intra_pan | dam | FCF_VER_2003); - hdr->fcf |= (uint16_t)(sam); - hdr->fcf = short_be(hdr->fcf); // Convert to IEEE endianness - - hdr->seq = seq; // Sequence number - - /* Convert addresses to IEEE-endianness */ - pan.addr = short_be(pan.addr); - addr_802154_to_ieee(&src); - addr_802154_to_ieee(&dst); - - /* Fill in the addresses */ - memcpy(&hdr->pan_id, &pan.addr, SIZE_6LOWPAN_SHORT); - memcpy(addresses, dst.addr.data, SIZE_6LOWPAN(dst.mode)); - memcpy(addresses + SIZE_6LOWPAN(dst.mode), src.addr.data,SIZE_6LOWPAN(src.mode)); -} - -#endif /* PICO_6LOWPAN_NOMAC */ - -/* Removes the IEEE802.15.4 MAC header before the frame */ -static int32_t -pico_802154_process_in(struct pico_frame *f) -{ -#ifndef PICO_6LOWPAN_NOMAC - struct pico_802154_hdr *hdr = (struct pico_802154_hdr *)f->net_hdr; - uint16_t fcf = short_be(hdr->fcf); - uint8_t hlen = 0; - f->src.pan = frame_802154_src(hdr); - f->dst.pan = frame_802154_dst(hdr); - - /* I claim the datalink header */ - f->datalink_hdr = f->net_hdr; - - if (fcf & FCF_SEC) { - f->flags |= PICO_FRAME_FLAG_LL_SEC; - } - - hlen = frame_802154_hdr_len(hdr); - - /* XXX: Generic procedure to move forward in incoming processing function - * is updating the net_hdr-pointer */ - f->net_hdr = f->datalink_hdr + (int32_t)hlen; - - return (int32_t)hlen; -#else - IGNORE_PARAMETER(f); - return 0; -#endif -} - -/* Prepends the IEEE802.15.4 MAC header before the frame */ -static int32_t -pico_802154_process_out(struct pico_frame *f) -{ -#ifndef PICO_6LOWPAN_NOMAC - int32_t len = (int32_t)(SIZE_802154_MHR_MIN + SIZE_6LOWPAN(f->dst.pan.mode) + SIZE_6LOWPAN(f->src.pan.mode)); - uint8_t sec = (uint8_t)((f->flags & PICO_FRAME_FLAG_LL_SEC) ? (FCF_SEC) : (FCF_NO_SEC)); - struct pico_6lowpan_info *info = (struct pico_6lowpan_info *)f->dev->eth; - uint16_t headroom = (uint16_t)(f->net_hdr - f->buffer); - static uint8_t seq = 0; - uint32_t grow = 0; - int32_t ret = 0; - - if (headroom < (uint16_t)len) { /* Check if there's enough headroom to prepend 802.15.4 header */ - grow = (uint32_t)(len - headroom); - ret = pico_frame_grow_head(f, (uint32_t)(f->buffer_len + grow)); - if (ret) { - pico_frame_discard(f); - return -1; - } - } - - /* XXX: General procedure to seek backward in an outgoing processing function - * is to update the datalink_hdr */ - f->datalink_hdr = f->datalink_hdr - len; - - /* Format the IEEE802.15.4 header */ - frame_802154_format(f->datalink_hdr, seq++, FCF_INTRA_PAN, FCF_NO_ACK_REQ, sec, info->pan_id, f->src.pan, f->dst.pan); - return len; -#else - IGNORE_PARAMETER(f); - return 0; -#endif -} - -/* Get the EUI-64 of the device in a structured form */ -static struct pico_802154 -addr_802154_ext_dev(struct pico_6lowpan_info *info) -{ - struct pico_802154 addr; - memcpy(addr.addr.data, info->addr_ext.addr, SIZE_6LOWPAN_EXT); - addr.mode = AM_6LOWPAN_EXT; - return addr; -} - -/* Get the short address of the device in a structured form */ -static struct pico_802154 -addr_802154_short_dev(struct pico_6lowpan_info *info) -{ - struct pico_802154 addr; - memcpy(addr.addr.data, (uint8_t *)&(info->addr_short.addr), SIZE_6LOWPAN_SHORT); - addr.mode = AM_6LOWPAN_SHORT; - return addr; -} - -/* Based on the source IPv6-address, this function derives the link layer source - * address */ -static struct pico_802154 -addr_802154_ll_src(struct pico_frame *f) -{ - struct pico_ip6 src = ((struct pico_ipv6_hdr *)f->net_hdr)->src; - if (IID_16(&src.addr[8])) { - /* IPv6 source is derived from the device's short address, use that - * short address so decompressor can derive the IPv6 source from - * the encapsulating header */ - return addr_802154_short_dev((struct pico_6lowpan_info *)f->dev->eth); - } else { - /* IPv6 source is derived from the device's extended address, use - * the device's extended address so */ - return addr_802154_ext_dev((struct pico_6lowpan_info *)f->dev->eth); - } -} - -/* Based on the destination IPv6-address, this function derives the link layer - * destination address */ -static struct pico_802154 -addr_802154_ll_dst(struct pico_frame *f) -{ - struct pico_ip6 dst = ((struct pico_ipv6_hdr *)f->net_hdr)->dst; - struct pico_802154 addr = { .addr.data = { 0 }, .mode = 0 }; - addr.mode = AM_6LOWPAN_NONE; - - /* If the address is multicast use 802.15.4 BCAST address 0xFFFF */ - if (pico_ipv6_is_multicast(dst.addr)) { - addr.addr._short.addr = short_be(ADDR_802154_BCAST); - addr.mode = AM_6LOWPAN_SHORT; - } - /* If the address is link local derive the link layer address from the IID */ - else { // if (pico_ipv6_is_linklocal(dst.addr)) { - if (IID_16(&dst.addr[8])) { - addr.addr.data[0] = dst.addr[14]; - addr.addr.data[1] = dst.addr[15]; - addr.mode = AM_6LOWPAN_SHORT; - } else { - memcpy(addr.addr.data, &dst.addr[8], SIZE_6LOWPAN_EXT); - addr.addr.data[0] = (uint8_t)(addr.addr.data[0] ^ 0x02); - addr.mode = AM_6LOWPAN_EXT; - } - } -/* - else { - struct pico_802154 *n = (struct pico_802154 *)pico_ipv6_get_neighbor(f); - if (n) { - memcpy(addr.addr.data, n->addr.data, SIZE_6LOWPAN(n->mode)); - addr.mode = n->mode; - } else { - pico_ipv6_nd_postpone(f); - } - } -*/ - return addr; -} - -/* Estimates the size the MAC header would be based on the source and destination - * link layer address */ -static int32_t -pico_802154_estimator(struct pico_frame *f) -{ - return (int32_t)(SIZE_802154_MHR_MIN + SIZE_6LOWPAN(f->src.pan.mode) + SIZE_6LOWPAN(f->dst.pan.mode) + f->dev->overhead); -} - -/* Retrieve address from temporarily flat buffer */ -static int32_t -addr_802154_from_buf(union pico_ll_addr *addr, uint8_t *buf) -{ - uint8_t len = (uint8_t)*buf++; - - if (len > 8) // OOB check - return -1; - - memcpy(addr->pan.addr.data, buf, len); - if (SIZE_6LOWPAN_EXT == len) - addr->pan.mode = AM_6LOWPAN_EXT; - else if (SIZE_6LOWPAN_SHORT == len) - addr->pan.mode = AM_6LOWPAN_SHORT; - else - addr->pan.mode = AM_6LOWPAN_NONE; - - return 0; -} - -/* If 'dest' is not set, this function will get the link layer address for a - * certain source IPv6 address, if 'dest' is set it will get it for the a - * destination address */ -static int32_t -addr_802154_from_net(union pico_ll_addr *addr, struct pico_frame *f, int32_t dest) -{ - if (dest) { - addr->pan = addr_802154_ll_dst(f); - } else { - addr->pan = addr_802154_ll_src(f); - } - return 0; -} - -/* Determines the length of an IEEE802.15.4 address */ -static int32_t -addr_802154_len(union pico_ll_addr *addr) -{ - return SIZE_6LOWPAN(addr->pan.mode); -} - -/* Compares 2 IEE802.15.4 addresses */ -static int32_t -addr_802154_cmp(union pico_ll_addr *a, union pico_ll_addr *b) -{ - if (a->pan.mode != b->pan.mode) { - return (int32_t)((int32_t)a->pan.mode - (int32_t)b->pan.mode); - } else { - return memcmp(a->pan.addr.data, b->pan.addr.data, SIZE_6LOWPAN(b->pan.mode)); - } -} - -/* Derive an IPv6 IID from an IEEE802.15.4 address */ -static int32_t -addr_802154_iid(uint8_t iid[8], union pico_ll_addr *addr) -{ - uint8_t buf[8] = {0,0,0,0xff,0xfe,0,0,0}; - struct pico_802154 pan = addr->pan; - - if (AM_6LOWPAN_SHORT == pan.mode) { - buf[6] = (uint8_t)(pan.addr._short.addr); - buf[7] = (uint8_t)(pan.addr._short.addr >> 8); - } else if (AM_6LOWPAN_EXT == pan.mode) { - memcpy(buf, pan.addr.data, SIZE_6LOWPAN_EXT); - buf[0] ^= (uint8_t)0x02; - } else { - return -1; - } - - memcpy(iid, buf, 8); - return 0; -} - -/* - * Allocates a pico_frame but makes sure the network-buffer starts on an 4-byte aligned address, - * this is required by upper layer of the stack. IEEE802.15.4's header isn't necessarily 4/8-byte - * aligned since the minimum size of an IEEE802.15.4 header is '5'. The datalink header therefore - * might not (and most probably isn't) aligned on an aligned address. The datalink header will of - * the size passed in 'headroom' - * - * @param size Size of the actual frame provided for network-layer and above - * @param headroom Size of the headroom for datalink-buffer - * @param overhead Size of the overhead to keep for the device driver - * - * @return struct pico_frame *, returns the allocated frame upon success, 'NULL' otherwise. - */ -static struct pico_frame * -pico_frame_alloc_with_headroom(uint16_t size, uint16_t headroom, uint16_t overhead) -{ - int network_offset = (((headroom + overhead) >> 2) + 1) << 2; // Sufficient headroom for alignment - struct pico_frame *f = pico_frame_alloc((uint32_t)(size + network_offset)); - - if (!f) - return NULL; - - f->net_hdr = f->buffer + network_offset; - f->datalink_hdr = f->net_hdr - headroom; - return f; -} - -/* Allocates a frame with the maximum MAC header size + device's overhead-parameter since this is - * the lowest level of the frame allocation chain */ -static struct pico_frame * -pico_802154_frame_alloc(struct pico_device *dev, uint16_t size) -{ - struct pico_frame *f = pico_frame_alloc_with_headroom(size, SIZE_802154_MHR_MAX, (uint16_t)dev->overhead); - if (!f) - return NULL; - - f->dev = dev; - return f; -} - -const struct pico_6lowpan_ll_protocol pico_6lowpan_ll_802154 = { - .process_in = pico_802154_process_in, - .process_out = pico_802154_process_out, - .estimate = pico_802154_estimator, - .addr_from_buf = addr_802154_from_buf, - .addr_from_net = addr_802154_from_net, - .addr_len = addr_802154_len, - .addr_cmp = addr_802154_cmp, - .addr_iid = addr_802154_iid, - .alloc = pico_802154_frame_alloc, -}; - -#endif /* PICO_SUPPORT_802154 */ diff --git a/ext/picotcp/modules/pico_802154.h b/ext/picotcp/modules/pico_802154.h deleted file mode 100644 index c2bcd7f..0000000 --- a/ext/picotcp/modules/pico_802154.h +++ /dev/null @@ -1,40 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights - reserved. See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ -#ifndef INCLUDE_PICO_802154 -#define INCLUDE_PICO_802154 - -#include "pico_device.h" -#include "pico_config.h" -#include "pico_6lowpan_ll.h" - -/******************************************************************************* - * Size definitions - ******************************************************************************/ - -#define MTU_802154_PHY (128u) -#define MTU_802154_MAC (125u) // 127 - Frame Check Sequence - -#define SIZE_802154_MHR_MIN (5u) -#define SIZE_802154_MHR_MAX (23u) -#define SIZE_802154_FCS (2u) -#define SIZE_802154_LEN (1u) -#define SIZE_802154_PAN (2u) - -/******************************************************************************* - * Structure definitions - ******************************************************************************/ - -PACKED_STRUCT_DEF pico_802154_hdr -{ - uint16_t fcf; - uint8_t seq; - uint16_t pan_id; -}; - -extern const struct pico_6lowpan_ll_protocol pico_6lowpan_ll_802154; - -#endif /* INCLUDE_PICO_802154 */ diff --git a/ext/picotcp/modules/pico_aodv.c b/ext/picotcp/modules/pico_aodv.c deleted file mode 100644 index b9726c7..0000000 --- a/ext/picotcp/modules/pico_aodv.c +++ /dev/null @@ -1,696 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ -#include -#include -#include -#include -#include - -#include -#ifdef PICO_SUPPORT_IPV4 - -#ifdef DEBUG_AODV - #define pico_aodv_dbg dbg -#else - #define pico_aodv_dbg(...) do {} while(0) -#endif - -#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; -} - -static PICO_TREE_DECLARE(aodv_nodes, aodv_node_compare); -static 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)); - - if (pico_tree_insert(&aodv_nodes, node)) { - PICO_FREE(node); - return NULL; - } - - 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: %lu now: %lu 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; - if (!pico_timer_add(AODV_PATH_DISCOVERY_TIME, aodv_reverse_path_discover, origin)) { - pico_aodv_dbg("AODV: Failed to start path discovery timer\n"); - } - } - } - - 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); -}; - -static 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); - - if (!pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(node->ring_ttl), aodv_retrans_rreq, node)) { - pico_aodv_dbg("AODV: Failed to start retransmission timer\n"); - } -} - -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++; - } - } - if (!pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(1), aodv_retrans_rreq, node)) { - pico_aodv_dbg("AODV: Failed to start retransmission timer\n"); - return -1; - } - 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); - } - } - if (!pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL)) { - pico_aodv_dbg("AODV: Failed to start collector timer\n"); - /* TODO what to do now? garbage collection will not be restarted, leading to memory leaks */ - } -} - -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(); - if (!pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL)) { - pico_aodv_dbg("AODV: Failed to start collector timer\n"); - pico_socket_close(aodv_socket); - aodv_socket = NULL; - return -1; - } - 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 2fa5cc9..0000000 --- a/ext/picotcp/modules/pico_aodv.h +++ /dev/null @@ -1,130 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 8b4b68f..0000000 --- a/ext/picotcp/modules/pico_arp.c +++ /dev/null @@ -1,566 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" -#include "pico_ethernet.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_datalink_send(f) <= 0) - 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++; - - if (!pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL)) { - arp_dbg("ARP: Failed to start update_max_arps timer\n"); - /* TODO if this fails all incoming arps will be discarded once max_arp_reqs recahes 0 */ - } -} - -void pico_arp_init(void) -{ - if (!pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL)) { - arp_dbg("ARP: Failed to start update_max_arps timer\n"); - } -} - -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); -} - -static 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); - } - - } - } - } -} - -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]) { - if (f->failure_count < 4) - frames_queued[i] = f; - - return; - } - } - /* Not possible to enqueue: caller will discard packet */ -} - - -#ifdef DEBUG_ARP -static 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 */ - if (!pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale)) { - arp_dbg("ARP: Failed to start expiration timer, destroying arp entry\n"); - pico_tree_delete(&arp_tree, stale); - PICO_FREE(stale); - } - } -} - -static int pico_arp_add_entry(struct pico_arp *entry) -{ - entry->arp_status = PICO_ARP_STATUS_REACHABLE; - entry->timestamp = PICO_TIME(); - - if (pico_tree_insert(&arp_tree, entry)) { - arp_dbg("ARP: Failed to insert new entry in tree\n"); - return -1; - } - - arp_dbg("ARP ## reachable.\n"); - pico_arp_queued_trigger(); - if (!pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry)) { - arp_dbg("ARP: Failed to start expiration timer\n"); - pico_tree_delete(&arp_tree, entry); - return -1; - } - - return 0; -} - -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; - - if (pico_arp_add_entry(arp) < 0) { - PICO_FREE(arp); - return -1; - } - - 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); - if (pico_arp_add_entry(found) < 0) { - arp_dbg("ARP: Failed to re-instert stale arp entry\n"); - PICO_FREE(found); - found = NULL; - } - } 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) { - pico_frame_discard(f); - 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 e292f4a..0000000 --- a/ext/picotcp/modules/pico_arp.h +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_ipc.c b/ext/picotcp/modules/pico_dev_ipc.c deleted file mode 100644 index f8b41e0..0000000 --- a/ext/picotcp/modules/pico_dev_ipc.c +++ /dev/null @@ -1,109 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - Authors: Michiel Kustermans - *********************************************************************/ - -#include -#include -#include - -#include "pico_device.h" -#include "pico_dev_ipc.h" -#include "pico_stack.h" - -struct pico_device_ipc { - struct pico_device dev; - int fd; -}; - -#define IPC_MTU 2048 - -static int pico_ipc_send(struct pico_device *dev, void *buf, int len) -{ - struct pico_device_ipc *ipc = (struct pico_device_ipc *) dev; - return (int)write(ipc->fd, buf, (uint32_t)len); -} - -static int pico_ipc_poll(struct pico_device *dev, int loop_score) -{ - struct pico_device_ipc *ipc = (struct pico_device_ipc *) dev; - struct pollfd pfd; - unsigned char buf[IPC_MTU]; - int len; - pfd.fd = ipc->fd; - pfd.events = POLLIN; - do { - if (poll(&pfd, 1, 0) <= 0) - return loop_score; - - len = (int)read(ipc->fd, buf, IPC_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_ipc_destroy(struct pico_device *dev) -{ - struct pico_device_ipc *ipc = (struct pico_device_ipc *) dev; - if(ipc->fd > 0) { - close(ipc->fd); - } -} - -static int ipc_connect(const char *sock_path) -{ - struct sockaddr_un addr; - int ipc_fd; - - if((ipc_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) { - return(-1); - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1); - addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; - - if(connect(ipc_fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) { - return(-1); - } - - return ipc_fd; -} - -struct pico_device *pico_ipc_create(const char *sock_path, const char *name, const uint8_t *mac) -{ - struct pico_device_ipc *ipc = PICO_ZALLOC(sizeof(struct pico_device_ipc)); - - if (!ipc) - return NULL; - - ipc->dev.mtu = IPC_MTU; - - if( 0 != pico_device_init((struct pico_device *)ipc, name, mac)) { - dbg("Ipc init failed.\n"); - pico_ipc_destroy((struct pico_device *)ipc); - return NULL; - } - - ipc->dev.overhead = 0; - ipc->fd = ipc_connect(sock_path); - if (ipc->fd < 0) { - dbg("Ipc creation failed.\n"); - pico_ipc_destroy((struct pico_device *)ipc); - return NULL; - } - - ipc->dev.send = pico_ipc_send; - ipc->dev.poll = pico_ipc_poll; - ipc->dev.destroy = pico_ipc_destroy; - dbg("Device %s created.\n", ipc->dev.name); - return (struct pico_device *)ipc; -} diff --git a/ext/picotcp/modules/pico_dev_ipc.h b/ext/picotcp/modules/pico_dev_ipc.h deleted file mode 100644 index 0df3d64..0000000 --- a/ext/picotcp/modules/pico_dev_ipc.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#ifndef INCLUDE_PICO_IPC -#define INCLUDE_PICO_IPC -#include "pico_config.h" -#include "pico_device.h" - -void pico_ipc_destroy(struct pico_device *ipc); -struct pico_device *pico_ipc_create(const char *sock_path, const char *name, const uint8_t *mac); - -#endif - diff --git a/ext/picotcp/modules/pico_dev_loop.c b/ext/picotcp/modules/pico_dev_loop.c deleted file mode 100644 index daba333..0000000 --- a/ext/picotcp/modules/pico_dev_loop.c +++ /dev/null @@ -1,66 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 bd22451..0000000 --- a/ext/picotcp/modules/pico_dev_loop.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 d87ff0f..0000000 --- a/ext/picotcp/modules/pico_dev_mock.c +++ /dev/null @@ -1,316 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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; -} - -static 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->dev); - 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_device_destroy(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); - - if (pico_tree_insert(&mock_device_tree, mock)) { - if (mock->mac != NULL) - PICO_FREE(mock->mac); - - pico_device_destroy(mock->dev); - - PICO_FREE(mock); - return NULL; - } - - 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 137f138..0000000 --- a/ext/picotcp/modules/pico_dev_mock.h +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 34e9ebc..0000000 --- a/ext/picotcp/modules/pico_dev_null.c +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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(const 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 321375b..0000000 --- a/ext/picotcp/modules/pico_dev_null.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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(const 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 387dbd9..0000000 --- a/ext/picotcp/modules/pico_dev_pcap.c +++ /dev/null @@ -1,96 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 37fb9d9..0000000 --- a/ext/picotcp/modules/pico_dev_pcap.h +++ /dev/null @@ -1,19 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 e778b16..0000000 --- a/ext/picotcp/modules/pico_dev_ppp.c +++ /dev/null @@ -1,2312 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - Authors: Serge Gadeyne, Daniele Lacamera, Maxime Vincent - - *********************************************************************/ - - -#include -#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" - -#ifdef DEBUG_PPP - #define ppp_dbg dbg -#else - #define ppp_dbg(...) do {} while(0) -#endif - -/* 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; -}; - -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; i < p[1] - 2; i++) - { - ppp_dbg(" %02X", p[2 + i]); - } - ppp_dbg("\n"); - - off = p[1]; - if (!off) - break; - - p += off; - } -} -#endif - -/* setting adjust_opts will adjust our options to the ones supplied */ -static uint16_t lcp_optflags(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len, int adjust_opts) -{ - uint16_t flags = 0; - uint8_t *p = pkt + sizeof(struct pico_lcp_hdr); - int off; - while(p < (pkt + len)) { - flags = (uint16_t)((uint16_t)(1u << (uint16_t)p[0]) | flags); - - if (adjust_opts && ppp) - { - switch (p[0]) - { - case LCPOPT_MRU: - /* XXX: Can we accept any MRU ? */ - ppp_dbg("Adjusting MRU to %02x%02x\n", p[2], p[3]); - ppp->mru = (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); - } - - if (!pico_timer_add(1000, pico_ppp_tick, arg)) { - ppp_dbg("PPP: Failed to start tick timer\n"); - /* TODO No more PPP ticks now */ - } -} - -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); - if (!ppp->timer) { - ppp_dbg("PPP: Failed to start tick timer\n"); - pico_device_destroy((struct pico_device*) ppp); - return NULL; - } - 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); - - pico_ipv4_cleanup_links(dev); - - 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 5d479c4..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 COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_radio_mgr.c b/ext/picotcp/modules/pico_dev_radio_mgr.c deleted file mode 100644 index 162caed..0000000 --- a/ext/picotcp/modules/pico_dev_radio_mgr.c +++ /dev/null @@ -1,357 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -/* - * For testing purposes. pico_dev_radio_manager allows simulating a mesh - * network for smoke tests. I previously used geomess, but that's another - * dependency to add then. Then @danielinux wrote the pico_dev_radiotest but - * that required adding a multicast route on the host which in its turn - * required 'sudo'. So I wrote a small simulator which doesn't require sudo. - * - Jelle - */ - -#include "pico_dev_radiotest.h" -#include "pico_addressing.h" -#include "pico_dev_tap.h" -#include "pico_802154.h" -#include "pico_device.h" -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_dev_radio_mgr.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG_RADIOTEST -#define RADIO_DBG dbg -#else -#define RADIO_DBG(...) do { } while (0) -#endif - -#define LISTENING_PORT 7777 -#define MESSAGE_MTU 150 -#define EVER (;;) - -struct socket { - int s; - uint8_t mgr; - uint8_t id; - uint8_t area0; - uint8_t area1; -}; - -/* Compare two application sockets */ -static int -pico_radio_mgr_sock_cmp(void *a, void *b) -{ - struct socket *sa = a, *sb = b; - return (int)(sa->id - sb->id); -} - -PICO_TREE_DECLARE(Sockets, pico_radio_mgr_sock_cmp); - -/* Insert a new socket in the tree */ -static int -pico_radio_mgr_socket_insert(int socket, uint8_t id, uint8_t area0, uint8_t area1, uint8_t mgr) -{ - struct socket *s = PICO_ZALLOC(sizeof(struct socket)); - if (s) { - s->area0 = area0; - s->area1 = area1; - s->s = socket; - s->mgr = mgr; - s->id = id; - if (!pico_tree_insert(&Sockets, s)) - return 0; - PICO_FREE(s); - } - return -1; -} - -/* Gather an array of poll descriptors with all sockets */ -static struct pollfd * -pico_radio_mgr_socket_all(int *n) -{ - struct pico_tree_node *i = NULL; - struct socket *key = NULL; - struct pollfd *fds = NULL; - int j = 1; - *n = 0; - - /* Retrieve all sockets */ - pico_tree_foreach(i, &Sockets) { - (*n)++; - } - - /* Create array from tree */ - fds = PICO_ZALLOC(sizeof(struct pollfd) * (size_t)*n); - if (fds) { - /* Put every socket in array */ - pico_tree_foreach(i, &Sockets) { - if (i && (key = i->keyValue)) { - if (!key->id) { - fds[0].fd = key->s; - fds[0].events = POLLIN; - } else { - fds[j].fd = key->s; - fds[j].events = POLLIN | POLLHUP; - j++; - } - } - } - } - - return fds; -} - -/* Get connection socket that belongs to a particular node */ -static struct socket * -pico_radio_mgr_socket_node(uint8_t id) -{ - struct socket test = { 0, 0, id }; - return pico_tree_findKey(&Sockets, &test); -} - -/* Handle POLLHUP event */ -static int -pico_radio_mgr_socket_hup(int socket) -{ - struct pico_tree_node *i = NULL; - struct socket *key = NULL; - - pico_tree_foreach(i, &Sockets) { - key = i->keyValue; - if (key && key->s == socket) { - pico_tree_delete(&Sockets, key); - RADIO_DBG("Radio %d detached from network\n", key->id); - PICO_FREE(key); - close(socket); - return 0; - } - } - return -1; -} - -/* Receive's an 'Hello'-message from the node that contains the id, the inserts - * an entry in the Sockets-tree */ -static int -pico_radio_mgr_welcome(int socket) -{ - int ret_len = sizeof(uint8_t); - uint8_t id = 0, area0, area1; - - errno = 0; - while ((ret_len = recv(socket, &id, (size_t)ret_len, 0)) != 1) { - if (errno && EINTR != errno) - goto hup; - } - while ((ret_len = recv(socket, &area0, (size_t)ret_len, 0)) != 1) { - if (errno && EINTR != errno) - goto hup; - } - while ((ret_len = recv(socket, &area1, (size_t)ret_len, 0)) != 1) { - if (errno && EINTR != errno) - goto hup; - } - - if (id <= 0) { // Node's can't have ID '0'. - RADIO_DBG("Invalid socket\n"); - close(socket); - return -1; - } - - RADIO_DBG("Connected to node %u in area %u and %u on socket %d.\n", id, area0, area1, socket); - if (pico_radio_mgr_socket_insert(socket, id, area0, area1, 0)) { - RADIO_DBG("Failed inserting new socket\n"); - close(socket); - return -1; - } - - return 0; -hup: - RADIO_DBG("recv() failed with error: %s\n", strerror(errno)); - close(socket); - return -1; -} - -/* Accepts a new TCP connection request */ -static int -pico_radio_mgr_accept(int socket) -{ - unsigned int len = sizeof(struct sockaddr_in); - struct sockaddr_in addr; - int s = accept(socket, (struct sockaddr *)&addr, &len); - if (s < 0) { - RADIO_DBG("Failed accepting connection\n"); - return s; - } else if (!s) { - RADIO_DBG("accept() returned file descriptor '%d'\n", s); - return s; - } - return pico_radio_mgr_welcome(s); -} - -/* Start listening for TCP connection requests on 'LISTENING_PORT' */ -static int -pico_radio_mgr_listen(void) -{ - struct sockaddr_in addr; - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - int ret = 0, yes = 1; - - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(LISTENING_PORT); - addr.sin_addr.s_addr = INADDR_ANY; - - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - - ret = bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); - if (ret < 0) { - RADIO_DBG("Failed binding socket to address: %s\n", strerror(ret)); - return -1; - } - - ret = listen(s, 5); - if (ret < 0) { - RADIO_DBG("Failed start listening\n"); - return -1; - } - - /* Also insert server socket in tree for polling */ - if (pico_radio_mgr_socket_insert(s, 0, 0, 0, 1)) { - close(s); - return -1; - } - - dbg("Started listening on port %d\n", LISTENING_PORT); - return s; -} - -/* Distribute received frame over all the areas where the node is attached to */ -static void -pico_radio_mgr_distribute(uint8_t *buf, int len, uint8_t id) -{ - struct socket *node = pico_radio_mgr_socket_node(id); - uint8_t area0 = 0, area1 = 0, ar0 = 0, ar1 = 0, phy = (uint8_t)len; - struct pico_tree_node *i = NULL; - struct socket *key = NULL; - if (node) { - RADIO_DBG("Received frame from node '%d' of '%d' bytes\n", id, len); - area0 = node->area0; - area1 = node->area1; - } else { - RADIO_DBG("Received frame from node not connected to network, weird..\n"); - return; - } - - pico_tree_foreach(i, &Sockets) { - key = i->keyValue; - if (key && key->id != id && key->id) { // Do not sent to ourselves or manager - ar0 = key->area0; - ar1 = key->area1; - if (area0 == ar0 || area0 == ar1 || (area1 && (area1 == ar0 || area1 == ar1))) { - len = (int)sendto(key->s, &phy, (size_t)1, 0, NULL, 0); - if (len != 1) return; - len = (int)sendto(key->s, buf, (size_t)phy, 0, NULL, 0); - if (len == (int)phy) - RADIO_DBG("Forwarded from '%u' of %d bytes sent to '%u'\n", id, len, key->id); - } - } - } -} - -/* Process poll-events */ -static void -pico_radio_mgr_process(struct pollfd *fds, int n) -{ - uint8_t buf[MESSAGE_MTU] = { 0 }, node = 0, phy = 0; - int i = 0, ret_len = 0; - short event = 0; - - for (i = 0; i < n; i++) { - event = fds[i].revents; - if (event && (event & POLLIN)) { // POLLIN - if (!i) { - /* Accept a new connection */ - pico_radio_mgr_accept(fds[i].fd); - continue; - } - - /* Read from node */ - ret_len = (int)recv(fds[i].fd, &phy, (size_t)1, 0); - if (ret_len <= 0) - goto hup; - ret_len = (int)recv(fds[i].fd, buf, (size_t)phy, 0); - if (ret_len <= 0 || ret_len != phy) - goto hup; - node = buf[ret_len - 2]; - pico_radio_mgr_distribute(buf, ret_len, node); - } else if (event && (event & POLLHUP)) { - goto hup; - } - } - - return; -hup: - pico_radio_mgr_socket_hup(fds[i].fd); -} - -static void -pico_radio_mgr_quit(int signum) -{ - struct pico_tree_node *i = NULL, *tmp = NULL; - struct socket *key = NULL; - IGNORE_PARAMETER(signum); - - dbg("Closing all sockets..."); - pico_tree_foreach_safe(i, &Sockets, tmp) { - key = i->keyValue; - if (key) { - pico_tree_delete(&Sockets, key); - shutdown(key->s, SHUT_RDWR); - PICO_FREE(key); - } - } - dbg("done.\n"); - exit(0); -} - -/* Create and start a radio-manager instance */ -int -pico_radio_mgr_start(void) -{ - int server = pico_radio_mgr_listen(); - struct pollfd *fds = NULL; - nfds_t n = 0; - int ret = 0; - if (server < 0) - return -1; - - signal(SIGQUIT, pico_radio_mgr_quit); - - for EVER { - if (fds) - PICO_FREE(fds); - fds = pico_radio_mgr_socket_all((int *)&n); - errno = 0; - ret = poll(fds, n, 1); - if (errno != EINTR && ret < 0) { - RADIO_DBG("Socket error: %s\n", strerror(ret)); - return ret; - } else if (!ret) { - continue; - } - pico_radio_mgr_process(fds, (int)n); - } -} diff --git a/ext/picotcp/modules/pico_dev_radio_mgr.h b/ext/picotcp/modules/pico_dev_radio_mgr.h deleted file mode 100644 index 37da415..0000000 --- a/ext/picotcp/modules/pico_dev_radio_mgr.h +++ /dev/null @@ -1,14 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Jelle De Vleeschouwer - *********************************************************************/ - -#ifndef __PICO_DEV_RADIO_MGR_H_ -#define __PICO_DEV_RADIO_MGR_H_ - -/* Start listening for TCP connection requests on 'LISTENING_PORT' */ -int pico_radio_mgr_start(void); - -#endif diff --git a/ext/picotcp/modules/pico_dev_radiotest.c b/ext/picotcp/modules/pico_dev_radiotest.c deleted file mode 100644 index a1b75be..0000000 --- a/ext/picotcp/modules/pico_dev_radiotest.c +++ /dev/null @@ -1,486 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera, Jelle De Vleeschouwer - *********************************************************************/ - -/******************************************************************************* - * PicoTCP - ******************************************************************************/ - -#include "pico_dev_radiotest.h" -#include "pico_6lowpan_ll.h" -#include "pico_addressing.h" -#include "pico_dev_tap.h" -#include "pico_802154.h" -#include "pico_device.h" -#include "pico_config.h" -#include "pico_stack.h" - -/******************************************************************************* - * System sockets - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#define LISTENING_PORT 7777 -#define MESSAGE_MTU 150 - -#ifdef RADIO_PCAP -#include -#endif - -#ifdef DEBUG_RADIOTEST -#define RADIO_DBG dbg -#else -#define RADIO_DBG(...) do { } while (0) -#endif - -/******************************************************************************* - * Constants - ******************************************************************************/ - -/* Uncomment next line to enable Random packet loss (specify percentage) */ -//#define PACKET_LOSS 3 - -#define RFDEV_PANID 0xABCD -#define MC_ADDR_BE 0x010101EBU -#define LO_ADDR 0x0100007FU - -#define LOOP_MTU 127 - -/******************************************************************************* - * Type definitions - ******************************************************************************/ - -struct radiotest_radio { - struct pico_dev_6lowpan dev; - struct pico_6lowpan_info addr; - int sock0; - int sock1; -#ifdef RADIO_PCAP - pcap_t *pcap; - pcap_dumper_t *pcapd; -#endif -}; - -struct radiotest_frame -{ - uint8_t *buf; - int len; - uint32_t id; - union pico_ll_addr src; - union pico_ll_addr dst; -}; - -/******************************************************************************* - * Global variables - ******************************************************************************/ - -static int connection = 0; - -static uint32_t tx_id = 0; -static uint32_t rx_id = 0; - -/******************************************************************************* - * pcap - ******************************************************************************/ - -#ifdef RADIO_PCAP - -static void radiotest_pcap_open(struct radiotest_radio *dev, char *dump) -{ - char path[100]; - - /* Open offline packet capture */ -#ifdef PICO_SUPPORT_802154 - dev->pcap = pcap_open_dead(DLT_IEEE802_15_4, 65535); -#elif defined (PICO_SUPPORT_802154_NO_MAC) - dev->pcap = pcap_open_dead(DLT_RAW, 65535); -#endif - if (!dev->pcap) { - perror("LibPCAP"); - exit (1); - } - - /* Construct file path */ - snprintf(path, 100, dump, dev->addr); - - /* Open dump */ - dev->pcapd = pcap_dump_open(dev->pcap, path); - if (dev->pcapd) - dbg("PCAP Enabled\n"); - else - dbg("PCAP Disabled\n"); -} - -static void radiotest_pcap_write(struct radiotest_radio *dev, uint8_t *buf, int len) -{ - struct pcap_pkthdr ph; - if (!dev || !dev->pcapd) - return; - ph.caplen = (uint32_t)len; - ph.len = (uint32_t)len; - gettimeofday(&ph.ts, NULL); - pcap_dump((u_char *)dev->pcapd, &ph, buf); - pcap_dump_flush(dev->pcapd); -} - -#else - -static void radiotest_pcap_open(struct radiotest_radio *dev, char *dump) -{ - (void)dev; - (void)dump; -} - -static void radiotest_pcap_write(struct radiotest_radio *dev, uint8_t *buf, int len) -{ - (void)dev; - (void)buf; - (void)len; -} - -#endif - -static int radiotest_cmp(void *a, void *b) -{ - struct radiotest_frame *fa = (struct radiotest_frame *)a; - struct radiotest_frame *fb = (struct radiotest_frame *)b; - return (int)(fa->id - fb->id); -} - -PICO_TREE_DECLARE(LoopFrames, radiotest_cmp); - -static uint8_t *radiotest_nxt_rx(int *len, union pico_ll_addr *src, union pico_ll_addr *dst) -{ - struct radiotest_frame test, *found = NULL; - uint8_t *ret = NULL; - test.id = rx_id++; - - found = pico_tree_findKey(&LoopFrames, &test); - if (found) { - ret = found->buf; - *len = found->len; - *src = found->src; - *dst = found->dst; - pico_tree_delete(&LoopFrames, found); - PICO_FREE(found); - } else { - rx_id--; - } - return ret; -} - -static void radiotest_nxt_tx(uint8_t *buf, int len, union pico_ll_addr src, union pico_ll_addr dst) -{ - struct radiotest_frame *new = PICO_ZALLOC(sizeof(struct radiotest_frame)); - if (new) { - new->buf = PICO_ZALLOC((uint16_t)len); - if (new->buf) { - memcpy(new->buf, buf, (size_t)len); - new->len = len; - new->id = tx_id++; - new->src = src; - new->dst = dst; - if (pico_tree_insert(&LoopFrames, new)) { - PICO_FREE(new); - tx_id--; - } - } else { - PICO_FREE(new); - } - } -} - -static int pico_loop_send(struct pico_device *dev, void *buf, int len, union pico_ll_addr src, union pico_ll_addr dst) -{ - IGNORE_PARAMETER(dev); - if (len > LOOP_MTU) - return 0; - RADIO_DBG("Looping back frame of %d bytes.\n", len); - radiotest_nxt_tx(buf, len, src, dst); - return len; -} - -static int pico_loop_poll(struct pico_device *dev, int loop_score) -{ - union pico_ll_addr src, dst; - uint8_t *buf = NULL; - int len = 0; - - if (loop_score <= 0) - return 0; - - buf = radiotest_nxt_rx(&len, &src, &dst); - if (buf) { - RADIO_DBG("Receiving frame of %d bytes.\n", len); - pico_6lowpan_stack_recv(dev, buf, (uint32_t)len, &src, &dst); - PICO_FREE(buf); - loop_score--; - } - - return loop_score; -} - - -/* Generates a simple extended address */ -static void radiotest_gen_ex(struct pico_6lowpan_short addr_short, uint8_t *buf) -{ - uint16_t sh = addr_short.addr; - buf[0] = 0x00; - buf[1] = 0x00; - buf[2] = 0x00; - buf[3] = 0xaa; - buf[4] = 0xab; - buf[5] = 0x00; - buf[6] = (uint8_t)((uint8_t)(short_be(sh) & 0xFF00) >> 8u); - buf[7] = (uint8_t)(short_be(sh) & 0xFFu); -} - -/** - * Simulated CRC16-CITT Kermit generation - * - * @param buf uint8_t *, buffer to generate FCS for. - * @param len uint8_t, len of the buffer - * - * @return CITT Kermit CRC16 of the buffer - */ -static uint16_t calculate_crc16(uint8_t *buf, uint8_t len) -{ - uint16_t crc = 0x0000; - uint16_t q = 0, i = 0; - uint8_t c = 0; - - for (i = 0; i < len; i++) { - c = buf[i]; - q = (crc ^ c) & 0x0F; - crc = (uint16_t)((uint16_t)(crc >> 4) ^ (q * 0x1081)); - q = (crc ^ (c >> 4)) & 0xF; - crc = (uint16_t)((uint16_t)(crc >> 4) ^ (q * 0x1081)); - } - - return crc; -} - -/* Poll-function for the pico_device-structure */ -static int radiotest_poll(struct pico_device *dev, int loop_score) -{ - struct radiotest_radio *radio = (struct radiotest_radio *)dev; - union pico_ll_addr src = {0}, dst = {0}; - int pollret, ret_len; - struct pollfd p; - uint8_t buf[128]; - uint8_t phy = 0; - - if (loop_score <= 0) - return 0; - - if (!dev) - return loop_score; - - p.fd = connection; - p.events = POLLIN | POLLHUP; - - /* Poll for data from radio management */ - errno = 0; - pollret = poll(&p, (nfds_t)1, 1); - if (errno == EINTR || pollret == 0) - return loop_score; - - if (pollret < 0) { - fprintf(stderr, "Socket error %s!\n", strerror(errno)); - exit(5); - } - - if (p.revents & POLLIN) { - ret_len = (int)recv(connection, &phy, (size_t)1, 0); - if (ret_len != 1) return loop_score; - ret_len = (int)recv(connection, buf, (size_t)phy, 0); - if (ret_len != (int)phy) - return loop_score; - else if (!ret_len) { - RADIO_DBG("Radio manager detached from network\n"); - exit(1); - } - } - - if (ret_len < 2) { /* Not valid */ - return loop_score; - } - -#ifdef P_LOSS - long n = lrand48(); - n = n % 100; - if (n < P_LOSS) { - RADIO_DBG("Packet got lost!\n"); - return loop_score; - } -#endif - - /* ADDRESS FILTER */ - if (buf[ret_len - 1] != 0xFF && buf[ret_len - 1] != (uint8_t)short_be(radio->addr.addr_short.addr)) { - RADIO_DBG("Packet is not for me!\n"); - return loop_score; - } - - /* Get src and destination address */ - dst.pan.addr._ext = radio->addr.addr_ext; - src.pan.addr.data[3] = 0xAA; - src.pan.addr.data[4] = 0xAB; - src.pan.addr.data[7] = buf[ret_len - 1]; - src.pan.mode = AM_6LOWPAN_EXT; - ret_len -= 2; - - /* Write the received frame to the pcap-dump */ - radiotest_pcap_write(radio, buf, ret_len); - - /* Hand the frame over to pico */ - pico_6lowpan_stack_recv(dev, buf, (uint32_t)(ret_len - 2), &src, &dst); - loop_score--; - - return loop_score; -} - -#define RADIO_OVERHEAD 4 - -/* Send-function for the pico_device-structure */ -static int radiotest_send(struct pico_device *dev, void *_buf, int len, union pico_ll_addr src, union pico_ll_addr dst) -{ - struct radiotest_radio *radio = (struct radiotest_radio *)dev; - uint8_t *buf = PICO_ZALLOC((size_t)(len + RADIO_OVERHEAD)); - uint8_t phy = 0, did = 0; - uint16_t crc = 0; - int ret = 0, dlen = 0; - IGNORE_PARAMETER(src); - - if (!buf) - return -1; - - /* Try to get node-ID from address */ - if (dev && pico_6lowpan_lls[dev->mode].addr_len) { - dlen = pico_6lowpan_lls[dev->mode].addr_len(&dst); - if (dlen < 0) - return -1; - did = dst.pan.addr.data[dlen - 1]; - } - - /* Store the addresses in buffer for management */ - memcpy(buf, _buf, (size_t)len); - len = (uint16_t)(len + (uint16_t)RADIO_OVERHEAD); // CRC + ID - buf[len - 2] = (uint8_t)short_be(radio->addr.addr_short.addr); - buf[len - 1] = did; - - /* Generate FCS, keep pcap happy ... */ - crc = calculate_crc16(_buf, (uint8_t)(len - RADIO_OVERHEAD)); - memcpy(buf + len - RADIO_OVERHEAD, (void *)&crc, 2); - - /* Send frame to radio management */ - phy = (uint8_t)(len); - ret = (int)sendto(connection, &phy, 1, 0, NULL, 0); - if (ret != 1) - return -1; - ret = (int)sendto(connection, buf, (size_t)(len), 0, NULL, 0); - RADIO_DBG("Radio '%u' transmitted a frame of %d bytes.\n", buf[len - 2], ret); - - /* Write the sent frame to the pcap-dump */ - radiotest_pcap_write(radio, buf, len - 2); - - PICO_FREE(buf); - return ret; -} - -static int radiotest_hello(int s, uint8_t id, uint8_t area0, uint8_t area1) -{ - uint8_t buf[3] = { id, area0, area1 }; - if (sendto(s, buf, (size_t)3, 0, NULL, 0) != 3) { - RADIO_DBG("Radio '%u' failed to send hello message\n", id); - return -1; - } - - RADIO_DBG("Radio '%u' attached to network\n", id); - return s; -} - -static int radiotest_connect(uint8_t id, uint8_t area0, uint8_t area1) -{ - struct sockaddr_in addr; - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - int ret = 0; - - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(LISTENING_PORT); - inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); - - ret = connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); - if (ret) { - RADIO_DBG("Radio '%u' could not attach to network\n", id); - return ret; - } - - return radiotest_hello(s, id, area0, area1); -} - -static void -pico_radiotest_quit(int signum) -{ - IGNORE_PARAMETER(signum); - dbg("Quitting radiotest\n"); - exit(0); -} - -/* Creates a radiotest-device */ -struct pico_device *pico_radiotest_create(uint8_t addr, uint8_t area0, uint8_t area1, int loop, char *dump) -{ - struct radiotest_radio *radio = PICO_ZALLOC(sizeof(struct radiotest_radio)); - struct pico_dev_6lowpan *lp = (struct pico_dev_6lowpan *)radio; - if (!radio) - return NULL; - if (!addr || (addr && !area0)) { - RADIO_DBG("Usage (node): -6 [1-255],[1-255],[0-255] ...\n"); - } - - signal(SIGQUIT, pico_radiotest_quit); - - radio->addr.pan_id.addr = short_be(RFDEV_PANID); - radio->addr.addr_short.addr = short_be((uint16_t)addr); - radiotest_gen_ex(radio->addr.addr_short, radio->addr.addr_ext.addr); - RADIO_DBG("Radiotest short address: 0x%04X\n", short_be(radio->addr.addr_short.addr)); - RADIO_DBG("Radiotest ext address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - radio->addr.addr_ext.addr[0],radio->addr.addr_ext.addr[1], - radio->addr.addr_ext.addr[2],radio->addr.addr_ext.addr[3], - radio->addr.addr_ext.addr[4],radio->addr.addr_ext.addr[5], - radio->addr.addr_ext.addr[6],radio->addr.addr_ext.addr[7]); - - if (!loop) { - if ((connection = radiotest_connect(addr, area0, area1)) <= 0) { - return NULL; - } - if (pico_dev_6lowpan_init(lp, "radio", (uint8_t *)&radio->addr, LL_MODE_IEEE802154, MTU_802154_MAC, 0, radiotest_send, radiotest_poll)) { - RADIO_DBG("pico_device_init failed.\n"); - pico_device_destroy((struct pico_device *)lp); - return NULL; - } - } else { - if (pico_dev_6lowpan_init(lp, "radio", (uint8_t *)&radio->addr, LL_MODE_IEEE802154, MTU_802154_MAC, 0, pico_loop_send, pico_loop_poll)) { - RADIO_DBG("pico_device_init failed.\n"); - pico_device_destroy((struct pico_device *)lp); - return NULL; - } - } - - if (dump) { - dbg("Dump: %s\n", dump); - radiotest_pcap_open(radio, dump); - } - - return (struct pico_device *)lp; -} - diff --git a/ext/picotcp/modules/pico_dev_radiotest.h b/ext/picotcp/modules/pico_dev_radiotest.h deleted file mode 100644 index eb484ee..0000000 --- a/ext/picotcp/modules/pico_dev_radiotest.h +++ /dev/null @@ -1,16 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - Authors: Daniele Lacamera, Jelle De Vleeschouwer - *********************************************************************/ - -#ifndef INCLUDE_PICO_DEV_RADIOTEST -#define INCLUDE_PICO_DEV_RADIOTEST - -#include "pico_device.h" -#include "pico_config.h" - -struct pico_device *pico_radiotest_create(uint8_t addr, uint8_t area0, uint8_t area1, int loop, char *dump); - -#endif /* INCLUDE_PICO_DEV_RADIOTEST */ diff --git a/ext/picotcp/modules/pico_dev_tap.c b/ext/picotcp/modules/pico_dev_tap.c deleted file mode 100644 index 877941f..0000000 --- a/ext/picotcp/modules/pico_dev_tap.c +++ /dev/null @@ -1,230 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 tapdev_link_state = 0; - -static void sig_handler(int signo) -{ - if (signo == SIGUSR1) { - tapdev_link_state = 0; - } - - if (signo == SIGUSR2) { - tapdev_link_state = 1; - } -} - -static int tap_link_state(__attribute__((unused)) struct pico_device *self) -{ - return tapdev_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; - } - - /* Host's mac address is generated * by the host kernel and is - * retrieved via tap_get_mac(). - */ - if (tap_get_mac(name, mac) < 0) { - dbg("Tap mac query failed.\n"); - pico_tap_destroy((struct pico_device *)tap); - return NULL; - } - - /* To act as a second endpoint in the same subnet, the picoTCP - * app using the tap device must have a different mac address. - * For simplicity, we just add 1 to the last byte of the linux - * endpoint so the two addresses are consecutive. - */ - 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 384226e..0000000 --- a/ext/picotcp/modules/pico_dev_tap.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 252f32a..0000000 --- a/ext/picotcp/modules/pico_dev_tap_windows.c +++ /dev/null @@ -1,1101 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - */ -#ifdef DEBUG_TAP_GENERAL -#define dbg_tap dbg /* first level debug */ -#else -#define dbg_tap(...) do{} while(0) -#endif - -#ifdef DEBUG_TAP_INFO -#define dbg_tap_info dbg /* tap info messages */ -#else -#define dbg_tap_info(...) do{} while(0) -#endif - -#ifdef DEBUG_TAP_WIN -#define dbg_tap_win32 dbg /* second level detailed win32 debug */ -#else -#define dbg_tap_win32(...) do{} while(0) -#endif - -#ifdef DEBUG_TAP_REG -#define dbg_tap_reg dbg /* third level: registry debug */ -#else -#define dbg_tap_reg(...) do{} while(0) -#endif - -/* - * 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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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_tap_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 100644 index bdc6977..0000000 --- a/ext/picotcp/modules/pico_dev_tap_windows.h +++ /dev/null @@ -1,17 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 ef52354..0000000 --- a/ext/picotcp/modules/pico_dev_tap_windows_private.h +++ /dev/null @@ -1,89 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 148ad92..0000000 --- a/ext/picotcp/modules/pico_dev_tun.c +++ /dev/null @@ -1,110 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 85b9dbf..0000000 --- a/ext/picotcp/modules/pico_dev_tun.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 3358162..0000000 --- a/ext/picotcp/modules/pico_dev_vde.c +++ /dev/null @@ -1,122 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -/* Mockables */ -#if defined UNIT_TEST -# define MOCKABLE __attribute__((weak)) -#else -# define MOCKABLE -#endif - -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 *MOCKABLE 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 4b13087..0000000 --- a/ext/picotcp/modules/pico_dev_vde.h +++ /dev/null @@ -1,18 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 5b56962..0000000 --- a/ext/picotcp/modules/pico_dhcp_client.c +++ /dev/null @@ -1,1074 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - Authors: Kristof Roelants, Frederik Van Slycken, Maxime Vincent - *********************************************************************/ - - -#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) - -#ifdef DEBUG_DHCP_CLIENT - #define dhcpc_dbg dbg -#else - #define dhcpc_dbg(...) do {} while(0) -#endif - -/* 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 - -/* Mockables */ -#if defined UNIT_TEST -# define MOCKABLE __attribute__((weak)) -#else -# define MOCKABLE -#endif - -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; - uint32_t timer_id; -}; - -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 void pico_dhcp_client_callback(struct pico_dhcp_client_cookie *dhcpc, int code); - -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); -} -static 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; - - if (pico_tree_insert(&DHCPCookies, dhcpc)) { - PICO_FREE(dhcpc); - return NULL; - } - - 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 = ck->timer[type]; - - if (t) { - /* Stale timer, mark to be freed in the callback */ - t->state = DHCP_CLIENT_TIMER_STOPPED; - } - - /* allocate a new timer, the old one is still in the timer tree, and will be freed as soon as it expires */ - 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; - t->timer_id = pico_timer_add(time, pico_dhcp_client_timer_handler, t); - if (!t->timer_id) { - dhcpc_dbg("DHCP: Failed to start timer\n"); - PICO_FREE(t); - return NULL; - } - - /* store timer struct reference in cookie */ - 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) { - t->state = DHCP_CLIENT_TIMER_STOPPED; - if ((t->type == PICO_DHCPC_TIMER_INIT) && (dhcpc->state < DHCP_CLIENT_STATE_SELECTING)) { - /* this was an INIT timer */ - pico_dhcp_client_reinit(now, dhcpc); - } else if (t->type != PICO_DHCPC_TIMER_INIT) { - /* this was NOT an INIT timer */ - 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); - } - } - } - - /* stale timer, it's associated struct should be freed */ - if (t->state == DHCP_CLIENT_TIMER_STOPPED) - PICO_FREE(t); -} - -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; - pico_dhcp_client_callback(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++) - { - if (dhcpc->timer[i]) { - /* Do not cancel timer, but rather set it's state to be freed when it expires */ - dhcpc->timer[i]->state = DHCP_CLIENT_TIMER_STOPPED; - dhcpc->timer[i] = NULL; - } - } -} - -static int 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); - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, time * 1000, dhcpc)) - return -1; - - return 0; -} - -static int 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); - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_REQUEST, time * 1000, dhcpc)) - return -1; - - return 0; -} - -static int 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; - - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_RENEW, halftime * 1000, dhcpc)) - return -1; - - return 0; -} - -static int 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; - - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_REBIND, halftime * 1000, dhcpc)) - return -1; - - return 0; -} - -static int pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_cookie *dhcpc) -{ - - pico_dhcp_client_stop_timers(dhcpc); - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_T1, dhcpc->t1_time * 1000, dhcpc)) - goto fail; - - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_T2, dhcpc->t2_time * 1000, dhcpc)) - goto fail; - - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_LEASE, dhcpc->lease_time * 1000, dhcpc)) - goto fail; - - return 0; - -fail: - pico_dhcp_client_stop_timers(dhcpc); - return -1; -} - -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) { - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc)) - return -1; - - 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; - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc)) - return -1; - - return 0; - } - - if (pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER) < 0) { - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - if (!pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc)) - return -1; - - return 0; - } - - dhcpc->retry = 0; - dhcpc->init_timestamp = PICO_TIME_MS(); - if (pico_dhcp_client_start_init_timer(dhcpc) < 0) { - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - return -1; - } - - return 0; -} - -int MOCKABLE 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); - if (pico_dhcp_client_start_requesting_timer(dhcpc) < 0) - return -1; - - return 0; -} - -static void pico_dhcp_client_update_link(struct pico_dhcp_client_cookie *dhcpc) -{ - struct pico_ip4 any_address = { - 0 - }; - struct pico_ip4 address = { - 0 - }; - struct pico_ipv4_link *l; - - dbg("DHCP client: update link\n"); - - 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); - - /* 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); - } -} - -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_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 new ip address - * in case the new address doesn't match the old one */ - l = pico_ipv4_link_by_dev(dhcpc->dev); - if (dhcpc->address.addr != (l->address).addr) { - pico_dhcp_client_update_link(dhcpc); - } - - 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); - - dhcpc->retry = 0; - dhcpc->renew_time = dhcpc->t2_time - dhcpc->t1_time; - dhcpc->rebind_time = dhcpc->lease_time - dhcpc->t2_time; - if (pico_dhcp_client_start_reacquisition_timers(dhcpc) < 0) { - pico_dhcp_client_callback(dhcpc, PICO_DHCP_ERROR); - return -1; - } - - - *(dhcpc->uid) = dhcpc->xid; - pico_dhcp_client_callback(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)); - pico_dhcp_client_callback(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; - pico_dhcp_client_callback(dhcpc, PICO_DHCP_ERROR); - - return -1; - } - - dhcpc->retry = 0; - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - if (pico_dhcp_client_start_renewing_timer(dhcpc) < 0) { - pico_socket_close(dhcpc->s); - dhcpc->s = NULL; - pico_dhcp_client_callback(dhcpc, PICO_DHCP_ERROR); - - return -1; - } - - 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); - if (pico_dhcp_client_start_rebinding_timer(dhcpc) < 0) - return -1; - - 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); - - pico_dhcp_client_callback(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); - if (pico_dhcp_client_start_init_timer(dhcpc) < 0) - return -1; - break; - - case DHCP_CLIENT_STATE_REQUESTING: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - if (pico_dhcp_client_start_requesting_timer(dhcpc) < 0) - return -1; - break; - - case DHCP_CLIENT_STATE_RENEWING: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST); - if (pico_dhcp_client_start_renewing_timer(dhcpc) < 0) - return -1; - break; - - case DHCP_CLIENT_STATE_REBINDING: - pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER); - if (pico_dhcp_client_start_rebinding_timer(dhcpc) < 0) - return -1; - 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 }, -}; - -static void dhcp_action_call( int (*call)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf), struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf) -{ - if (call) - call(dhcpc, buf); -} - -/* 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"); - dhcp_action_call(dhcp_fsm[dhcpc->state].offer, dhcpc, buf); - break; - - case PICO_DHCP_MSG_ACK: - dhcpc_dbg("DHCP client: received ACK\n"); - dhcp_action_call(dhcp_fsm[dhcpc->state].ack, dhcpc, buf); - break; - - case PICO_DHCP_MSG_NAK: - dhcpc_dbg("DHCP client: received NAK\n"); - dhcp_action_call(dhcp_fsm[dhcpc->state].nak, dhcpc, buf); - break; - - case PICO_DHCP_EVENT_T1: - dhcpc_dbg("DHCP client: received T1 timeout\n"); - dhcp_action_call(dhcp_fsm[dhcpc->state].timer1, dhcpc, buf); - break; - - case PICO_DHCP_EVENT_T2: - dhcpc_dbg("DHCP client: received T2 timeout\n"); - dhcp_action_call(dhcp_fsm[dhcpc->state].timer2, dhcpc, buf); - break; - - case PICO_DHCP_EVENT_LEASE: - dhcpc_dbg("DHCP client: received LEASE timeout\n"); - dhcp_action_call(dhcp_fsm[dhcpc->state].timer_lease, dhcpc, buf); - break; - - case PICO_DHCP_EVENT_RETRANSMIT: - dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n"); - dhcp_action_call(dhcp_fsm[dhcpc->state].timer_retransmit, dhcpc, buf); - 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); -} - -static void pico_dhcp_client_callback(struct pico_dhcp_client_cookie *dhcpc, int code) -{ - if(dhcpc->cb) - dhcpc->cb(dhcpc, code); -} - -void *MOCKABLE pico_dhcp_get_identifier(uint32_t xid) -{ - return (void *)pico_dhcp_client_find_cookie(xid); -} - -struct pico_ip4 MOCKABLE pico_dhcp_get_address(void*dhcpc) -{ - return ((struct pico_dhcp_client_cookie*)dhcpc)->address; -} - -struct pico_ip4 MOCKABLE 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 8ec8e27..0000000 --- a/ext/picotcp/modules/pico_dhcp_client.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 ccd15f2..0000000 --- a/ext/picotcp/modules/pico_dhcp_common.c +++ /dev/null @@ -1,190 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 4ccdc67..0000000 --- a/ext/picotcp/modules/pico_dhcp_common.h +++ /dev/null @@ -1,191 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 03ce387..0000000 --- a/ext/picotcp/modules/pico_dhcp_server.c +++ /dev/null @@ -1,426 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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) - -#ifdef DEBUG_DHCP_SERVER - #define dhcps_dbg dbg -#else - #define dhcps_dbg(...) do {} while(0) -#endif - -/* 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); -} -static 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); -} -static 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; - } - - if (pico_tree_insert(&DHCPSettings, dhcps)) { - dhcps_dbg("DHCP server ERROR: could not insert settings in tree\n"); - PICO_FREE(dhcps); - return NULL; - } - - 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); - if (pico_tree_insert(&DHCPNegotiations, dhcpn)) { - dhcps_dbg("DHCP server ERROR: could not insert negotiations in tree\n"); - PICO_FREE(dhcpn); - return NULL; - } - - 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 45a9b1b..0000000 --- a/ext/picotcp/modules/pico_dhcp_server.h +++ /dev/null @@ -1,34 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 cf283cc..0000000 --- a/ext/picotcp/modules/pico_dns_client.c +++ /dev/null @@ -1,846 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -#ifdef DEBUG_DNS - #define dns_dbg dbg -#else - #define dns_dbg(...) do {} while(0) -#endif - -/* 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); -} -static 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); -} -static 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 or out of memory */ - PICO_FREE(dns); - if ((void *)found == (void *)&LEAF) - return NULL; - else - 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) { - if ((void *)found != (void *)&LEAF) /* If found == &LEAF we're out of memory and pico_err is set */ - 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", long_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; - if (!pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID)) { - dns_dbg("DNS: Failed to start retransmission timer\n"); - goto failure; - } - - 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_check_rdlength(uint16_t qtype, uint16_t rdlength) -{ - switch (qtype) - { - case PICO_DNS_TYPE_A: - if (rdlength != PICO_DNS_RR_A_RDLENGTH) - return -1; - break; -#ifdef PICO_SUPPORT_IPV6 - case PICO_DNS_TYPE_AAAA: - if (rdlength != PICO_DNS_RR_AAAA_RDLENGTH) - return -1; - break; -#endif - default: - break; - } - - return 0; -} - -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); - - if (pico_dns_client_check_rdlength(q->qtype, short_be(asuffix->rdlength)) < 0) { - dns_dbg("DNS ERROR: Invalid RR rdlength: %u\n", short_be(asuffix->rdlength)); - return -1; - } - - 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; -} - -extern 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); -} - - -extern 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); -} - -extern 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; -} - -extern 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 - -extern 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 437d558..0000000 --- a/ext/picotcp/modules/pico_dns_client.h +++ /dev/null @@ -1,58 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -/* RDLENGTH for A and AAAA RR's */ -#define PICO_DNS_RR_A_RDLENGTH 4 -#define PICO_DNS_RR_AAAA_RDLENGTH 16 - -#ifdef __cplusplus -extern "C" { -#endif - -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 - -#ifdef __cplusplus -} -#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 44d89da..0000000 --- a/ext/picotcp/modules/pico_dns_common.c +++ /dev/null @@ -1,1784 +0,0 @@ -/* **************************************************************************** - * PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - * See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" - -#ifdef DEBUG_DNS - #define dns_dbg dbg -#else - #define dns_dbg(...) do {} while(0) -#endif - -/* MARK: v NAME & IP FUNCTIONS */ -#define dns_name_foreach_label_safe(label, name, next, maxlen) \ - for ((label) = (name), (next) = (char *)((name) + *(unsigned char*)(name) + 1); \ - (*(label) != '\0') && ((uint16_t)((label) - (name)) < (maxlen)); \ - (label) = (next), (next) = (char *)((next) + *(unsigned char*)(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, (uint16_t)(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, uint16_t maxlen ) -{ - char c = '\0'; - char *lbl = url, *i = url; - - /* Check params */ - if (!url || pico_dns_check_namelen(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, uint16_t maxlen ) -{ - char *label = NULL, *next = NULL; - - /* Iterate safely over the labels and update each label */ - dns_name_foreach_label_safe(label, ptr, next, 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 - * generated 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. Should be either - * PICO_DNS_CASE_SENSITIVE or PICO_DNS_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), PICO_DNS_CASE_INSENSITIVE); -} - -/* **************************************************************************** - * 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), PICO_DNS_CASE_INSENSITIVE); -} - -/* **************************************************************************** - * 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), PICO_DNS_CASE_SENSITIVE); -} - -/* 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 questions & - * 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"); - PICO_FREE(packet); - 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"); - PICO_FREE(packet); - 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 8272128..0000000 --- a/ext/picotcp/modules/pico_dns_common.h +++ /dev/null @@ -1,528 +0,0 @@ - -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -/* Used in pico_dns_rdata_cmp */ -#define PICO_DNS_CASE_SENSITIVE 0x00u -#define PICO_DNS_CASE_INSENSITIVE 0x01u - -#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, uint16_t 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, uint16_t 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. Should be either - * PICO_DNS_CASE_SENSITIVE or PICO_DNS_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 d845b73..0000000 --- a/ext/picotcp/modules/pico_dns_sd.c +++ /dev/null @@ -1,568 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - . - Author: Jelle De Vleeschouwer - *********************************************************************/ - -#include "pico_dns_sd.h" - -#ifdef PICO_SUPPORT_DNS_SD - -/* --- Debugging --- */ -#ifdef DEBUG_DNS_SD - #define dns_sd_dbg dbg -#else - #define dns_sd_dbg(...) do {} while(0) -#endif - -/* --- 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 its 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) { - if (pico_tree_insert(&rtree, txt_record) == &LEAF) { - PICO_MDNS_RTREE_DESTROY(&rtree); - pico_mdns_record_delete((void **)&txt_record); - pico_mdns_record_delete((void **)&srv_record); - return -1; - } - } - - if (pico_tree_insert(&rtree, srv_record) == &LEAF) { - PICO_MDNS_RTREE_DESTROY(&rtree); - pico_mdns_record_delete((void **)&srv_record); - return -1; - } - - if (pico_mdns_claim(rtree, callback, arg)) { - PICO_MDNS_RTREE_DESTROY(&rtree); - return -1; - } - - /* Only destroy the tree, not its elements since they still exist in another tree */ - 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 ec9f727..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 COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_ethernet.c b/ext/picotcp/modules/pico_ethernet.c deleted file mode 100644 index cc86e85..0000000 --- a/ext/picotcp/modules/pico_ethernet.c +++ /dev/null @@ -1,447 +0,0 @@ - /********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_icmp4.h" -#include "pico_icmp6.h" -#include "pico_arp.h" -#include "pico_ethernet.h" - -#define IS_LIMITED_BCAST(f) (((struct pico_ipv4_hdr *) f->net_hdr)->dst.addr == PICO_IP4_BCAST) - -#ifdef PICO_SUPPORT_ETH - -const uint8_t PICO_ETHADDR_ALL[6] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -# define PICO_SIZE_MCAST 3 -static const uint8_t PICO_ETHADDR_MCAST[6] = { - 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 -}; - -#ifdef PICO_SUPPORT_IPV6 -# define PICO_SIZE_MCAST6 2 -static const uint8_t PICO_ETHADDR_MCAST6[6] = { - 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 -}; -#endif - -/* 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. - */ - -/* Queues */ -static struct pico_queue ethernet_in = { - 0 -}; -static struct pico_queue ethernet_out = { - 0 -}; - -int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f); -static int32_t pico_ethernet_receive(struct pico_frame *f); - -static int pico_ethernet_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - return pico_ethernet_send(f); -} - -static int pico_ethernet_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - IGNORE_PARAMETER(self); - return (pico_ethernet_receive(f) <= 0); /* 0 on success, which is ret > 0 */ -} - -static struct pico_frame *pico_ethernet_alloc(struct pico_protocol *self, struct pico_device *dev, uint16_t size) -{ - struct pico_frame *f = NULL; - uint32_t overhead = 0; - IGNORE_PARAMETER(self); - - if (dev) - overhead = dev->overhead; - - f = pico_frame_alloc((uint32_t)(overhead + size + PICO_SIZE_ETHHDR)); - if (!f) - return NULL; - - f->dev = dev; - f->datalink_hdr = f->buffer + overhead; - f->net_hdr = f->datalink_hdr + PICO_SIZE_ETHHDR; - /* Stay of the rest, higher levels will take care */ - - return f; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_ethernet = { - .name = "ethernet", - .layer = PICO_LAYER_DATALINK, - .alloc = pico_ethernet_alloc, - .process_in = pico_ethernet_process_in, - .process_out = pico_ethernet_process_out, - .q_in = ðernet_in, - .q_out = ðernet_out, -}; - -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)) { - if (pico_enqueue(pico_proto_ipv4.q_in, f) < 0) { - pico_frame_discard(f); - return -1; - } - } 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)) { - if (pico_enqueue(pico_proto_ipv6.q_in, f) < 0) { - pico_frame_discard(f); - return -1; - } - } else { - /* Wrong version for link layer type */ - pico_frame_discard(f); - return -1; - } - - return (int32_t)f->buffer_len; -} -#endif - -static int32_t pico_eth_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_eth_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; -} - -static 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_eth_check_bcast(f); - return pico_eth_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"); - if (pico_ethernet_receive(clone) < 0) { - dbg("pico_ethernet_receive() failed\n"); - } - 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) -{ - return (pico_sendto_dev(f) > 0); // Return 1 on success, ret > 0 -} - -/* Checks whether or not there's enough headroom allocated in the frame to - * prepend the Ethernet header. Reallocates if this is not the case. */ -static int eth_check_headroom(struct pico_frame *f) -{ - uint32_t headroom = (uint32_t)(f->net_hdr - f->buffer); - uint32_t grow = (uint32_t)(PICO_SIZE_ETHHDR - headroom); - if (headroom < (uint32_t)PICO_SIZE_ETHHDR) { - return pico_frame_grow_head(f, (uint32_t)(f->buffer_len + grow)); - } - return 0; -} - -/* 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) - { - /* Enqueue copy of frame in IPv6 ND-module to retry later. Discard - * frame, otherwise we have a duplicate in IPv6-ND */ - pico_ipv6_nd_postpone(f); - return (int32_t)f->len; - } - - 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 { - /* Enqueue copy of frame in ARP-module to retry later. Discard - * frame otherwise we have a duplicate */ - pico_arp_postpone(f); - return (int32_t)f->len; - } - } -#endif - - /* This sets destination and source address, then pushes the packet to the device. */ - if (dstmac_valid) { - struct pico_eth_hdr *hdr; - if (!eth_check_headroom(f)) { - 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 successfully. - * Lower level queue has frame, so don't discard */ - return (int32_t)f->len; - } - } - } - - /* Failure, frame could not be be enqueued in lower-level layer, safe - * to discard since something clearly went wrong */ - pico_frame_discard(f); - return 0; -} - -#endif /* PICO_SUPPORT_ETH */ - - diff --git a/ext/picotcp/modules/pico_ethernet.h b/ext/picotcp/modules/pico_ethernet.h deleted file mode 100644 index e60c467..0000000 --- a/ext/picotcp/modules/pico_ethernet.h +++ /dev/null @@ -1,18 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - -#ifndef INCLUDE_PICO_ETHERNET -#define INCLUDE_PICO_ETHERNET - -#include "pico_config.h" -#include "pico_frame.h" - -extern struct pico_protocol pico_proto_ethernet; - -#endif /* INCLUDE_PICO_ETHERNET */ diff --git a/ext/picotcp/modules/pico_fragments.c b/ext/picotcp/modules/pico_fragments.c deleted file mode 100644 index 81b92ed..0000000 --- a/ext/picotcp/modules/pico_fragments.c +++ /dev/null @@ -1,573 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" - -#ifdef DEBUG_FRAG - #define frag_dbg dbg -#else - #define frag_dbg(...) do {} while(0) -#endif - -#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)(((uint32_t)x->ext.frag.id[0] << 24) + ((uint32_t)x->ext.frag.id[1] << 16) + \ - ((uint32_t)x->ext.frag.id[2] << 8) + (uint32_t)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 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(struct pico_tree *tree, uint8_t proto, uint8_t net); -static int pico_fragments_reassemble(struct pico_tree *tree, unsigned int len, uint8_t proto, uint8_t net); -static int pico_fragments_get_more_flag(struct pico_frame *frame, uint8_t net); -static uint32_t pico_fragments_get_offset(struct pico_frame *frame, uint8_t net); -static void pico_fragments_send_notify(struct pico_frame *first); -static uint16_t pico_fragments_get_header_length(uint8_t net); -static void pico_fragments_empty_tree(struct pico_tree *tree); - -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) -static uint32_t ipv6_cur_frag_id = 0u; -static 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; -} -static PICO_TREE_DECLARE(ipv6_fragments, pico_ipv6_frag_compare); - -static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto) -{ - if (pico_fragments_reassemble(&ipv6_fragments, len, proto, PICO_PROTO_IPV6) == 0) - { - 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); - if (!ipv6_fragments_timer) { - frag_dbg("FRAG: Failed to start IPv6 expiration timer\n"); - pico_fragments_empty_tree(&ipv6_fragments); - } -} - -static int pico_ipv6_frag_match(struct pico_frame *a, struct pico_frame *b) -{ - struct pico_ipv6_hdr *ha = NULL, *hb = NULL; - if (!a || !b) - return -1; - - ha = (struct pico_ipv6_hdr *)a->net_hdr; - hb = (struct pico_ipv6_hdr *)b->net_hdr; - if (!ha || !hb) - return -2; - - if (memcmp(ha->src.addr, hb->src.addr, PICO_SIZE_IP6) != 0) - return 1; - - if (memcmp(ha->dst.addr, hb->dst.addr, PICO_SIZE_IP6) != 0) - return 2; - - return 0; -} -#endif - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) -static uint32_t ipv4_cur_frag_id = 0u; -static 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; -} -static PICO_TREE_DECLARE(ipv4_fragments, pico_ipv4_frag_compare); - -static void pico_ipv4_fragments_complete(unsigned int len, uint8_t proto) -{ - if (pico_fragments_reassemble(&ipv4_fragments, len, proto, PICO_PROTO_IPV4) == 0) - { - 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); - if (!ipv4_fragments_timer) { - frag_dbg("FRAG: Failed to start IPv4 expiration timer\n"); - pico_fragments_empty_tree(&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 -1; - - ha = (struct pico_ipv4_hdr *)a->net_hdr; - hb = (struct pico_ipv4_hdr *)b->net_hdr; - if (!ha || !hb) - return -2; - - if (memcmp(&(ha->src.addr), &(hb->src.addr), PICO_SIZE_IP4) != 0) - return 1; - - if (memcmp(&(ha->dst.addr), &(hb->dst.addr), PICO_SIZE_IP4) != 0) - return 2; - - return 0; -} -#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 void pico_fragments_empty_tree(struct pico_tree *tree) -{ - struct pico_tree_node *index, *tmp; - - if (!tree) - { - return; - } - - pico_tree_foreach_safe(index, tree, tmp) { - struct pico_frame * old = index->keyValue; - pico_tree_delete(tree, old); - pico_frame_discard(old); - } - -} - -static int pico_fragments_check_complete(struct pico_tree *tree, uint8_t proto, uint8_t net) -{ - struct pico_tree_node *index, *temp; - struct pico_frame *cur; - unsigned int bookmark = 0; - - if (!tree) - return 0; - - pico_tree_foreach_safe(index, tree, temp) { - cur = index->keyValue; - if (cur) { - if (pico_fragments_get_offset(cur, net) != bookmark) - return -1; - - bookmark += cur->transport_len; - if (!pico_fragments_get_more_flag(cur, net)) { - pico_fragments_complete(bookmark, proto, net); - return 0; - } - } - } - return 1; -} - -static void pico_frag_expire(pico_time now, void *arg) -{ - struct pico_tree *tree = (struct pico_tree *) arg; - struct pico_frame *first = NULL; - IGNORE_PARAMETER(now); - - if (!tree) - { - frag_dbg("Expired packet but no tree supplied!\n"); - return; - } - - first = pico_tree_first(tree); - - if (!first) { - frag_dbg("Empty tree - not sending notify\n"); - return; - } - - pico_fragments_send_notify(first); - - pico_fragments_empty_tree(tree); -} - -static void pico_fragments_send_notify(struct pico_frame *first) -{ - uint8_t net = 0; - - if (!first) - { - return; - } - - if (0) {} - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - else 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) - else if (IS_IPV6(first)) - { - net = PICO_PROTO_IPV6; - frag_dbg("Packet expired! ID:%hu\n", ipv6_cur_frag_id); - } - -#endif - - if (((pico_fragments_get_offset(first, net) == 0) && (pico_frame_dst_is_unicast(first)))) - { - frag_dbg("sending notify\n"); - pico_notify_frag_expired(first); - } - else - { - frag_dbg("Not first packet or not unicast address, not sending notify"); - } -} - -static int pico_fragments_reassemble(struct pico_tree *tree, unsigned int len, uint8_t proto, uint8_t net) -{ - struct pico_tree_node *index, *tmp; - struct pico_frame *f; - uint16_t header_length = 0; - unsigned int bookmark = 0; - struct pico_frame *full = NULL; - struct pico_frame *first = NULL; - - if (!tree) - { - frag_dbg("Cannot reassemble packet, no tree supplied!\n"); - return -1; - } - - first = pico_tree_first(tree); - - if (!first) - { - frag_dbg("Cannot reassemble packet, empty tree supplied!\n"); - return -2; - } - - header_length = pico_fragments_get_header_length(net); - - if (!header_length) - { - return -3; - } - - full = pico_frame_alloc((uint16_t)(header_length + len)); - if (full) { - full->net_hdr = full->buffer; - full->net_len = header_length; - 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, tree, tmp) { - f = index->keyValue; - memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len); - bookmark += f->transport_len; - pico_tree_delete(tree, f); - pico_frame_discard(f); - } - if (pico_transport_receive(full, proto) == -1) - { - pico_frame_discard(full); - } - - return 0; - } - - return 1; -} - -static uint16_t pico_fragments_get_header_length(uint8_t net) -{ - if (0) {} - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - else if (net == PICO_PROTO_IPV4) - { - return PICO_SIZE_IP4HDR; - } -#endif -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - else if (net == PICO_PROTO_IPV6) - { - return PICO_SIZE_IP6HDR; - } -#endif - - return 0; -} - -static int pico_fragments_get_more_flag(struct pico_frame *frame, uint8_t net) -{ - if (!frame) - { - frag_dbg("no frame given to determine more flag\n"); - return 0; - } - - if (0) {} - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - else if (net == PICO_PROTO_IPV4) - { - return IP4_FRAG_MORE(frame->frag); - } -#endif -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - else if (net == PICO_PROTO_IPV6) - { - return IP6_FRAG_MORE(frame->frag); - } -#endif - - return 0; -} - -static uint32_t pico_fragments_get_offset(struct pico_frame *frame, uint8_t net) -{ - if (!frame) - { - frag_dbg("no frame given to determine offset\n"); - return 0; - } - - if (0) {} - -#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG) - else if (net == PICO_PROTO_IPV4) - { - return IP4_FRAG_OFF(frame->frag); - } -#endif -#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG) - else if (net == PICO_PROTO_IPV6) - { - return IP6_FRAG_OFF(frame->frag); - } -#endif - - return 0; -} - -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 = NULL; - - if (!f || !frag) - { - frag_dbg("Bad arguments provided to pico_ipv6_process_frag\n"); - return; - } - - first = pico_tree_first(&ipv6_fragments); - - if (first) - { - if ((pico_ipv6_frag_match(f, first) == 0 && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id))) { - struct pico_frame *temp = NULL; - - temp = pico_frame_copy(f); - - if (!temp) { - frag_dbg("Could not allocate memory to continue reassembly of IPV6 fragmented packet (id: %hu)\n", ipv6_cur_frag_id); - return; - } - - if (pico_tree_insert(&ipv6_fragments, temp)) { - frag_dbg("FRAG: Could not insert picoframe in tree\n"); - pico_frame_discard(temp); - return; - } - } - } - else - { - struct pico_frame *temp = NULL; - - 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; - } - - temp = pico_frame_copy(f); - - if (!temp) { - frag_dbg("Could not allocate memory to start reassembly of fragmented packet\n"); - 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 (pico_tree_insert(&ipv6_fragments, temp)) { - frag_dbg("FRAG: Could not insert picoframe in tree\n"); - pico_frame_discard(temp); - return; - } - } - - pico_fragments_check_complete(&ipv6_fragments, 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 = NULL; - - if (!f || !hdr) - { - frag_dbg("Bad arguments provided to pico_ipv4_process_frag\n"); - return; - } - - first = pico_tree_first(&ipv4_fragments); - - if (first) - { - /* fragments from old packets still in tree, and new first fragment ? */ - if ((IP4_FRAG_ID(hdr) != ipv4_cur_frag_id) && (IP4_FRAG_OFF(f->frag) == 0)) { - pico_fragments_empty_tree(&ipv4_fragments); - - first = NULL; - ipv4_cur_frag_id = 0; - } - - if ((pico_ipv4_frag_match(f, first) == 0 && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id))) { - struct pico_frame *temp = NULL; - - temp = pico_frame_copy(f); - - if (!temp) { - frag_dbg("Could not allocate memory to continue reassembly of IPV4 fragmented packet (id: %hu)\n", ipv4_cur_frag_id); - return; - } - - if (pico_tree_insert(&ipv4_fragments, temp)) { - frag_dbg("FRAG: Could not insert picoframe in tree\n"); - pico_frame_discard(temp); - return; - } - } - } - else - { - struct pico_frame *temp = NULL; - - if (ipv4_cur_frag_id && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id)) { - /* Discard late arrivals, without firing the timer */ - return; - } - - temp = pico_frame_copy(f); - - if (!temp) { - frag_dbg("Could not allocate memory to start reassembly fragmented packet\n"); - return; - } - - pico_ipv4_frag_timer_on(); - ipv4_cur_frag_id = IP4_FRAG_ID(hdr); - frag_dbg("Started new reassembly, ID:%hu\n", ipv4_cur_frag_id); - - if (pico_tree_insert(&ipv4_fragments, temp)) { - frag_dbg("FRAG: Could not insert picoframe in tree\n"); - pico_frame_discard(temp); - return; - } - } - - pico_fragments_check_complete(&ipv4_fragments, 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 0c362cb..0000000 --- a/ext/picotcp/modules/pico_hotplug_detection.c +++ /dev/null @@ -1,207 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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; - struct pico_tree init_callbacks; /* functions we still need to call for initialization */ -}; - -static 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; -} - -static PICO_TREE_DECLARE(Hotplug_device_tree, pico_hotplug_dev_cmp); - -static void initial_callbacks(struct pico_hotplug_device *hpdev, int event) -{ - struct pico_tree_node *cb_node = NULL, *cb_safe = NULL; - void (*cb)(struct pico_device *dev, int event); - pico_tree_foreach_safe(cb_node, &(hpdev->init_callbacks), cb_safe) - { - cb = cb_node->keyValue; - cb(hpdev->dev, event); - pico_tree_delete(&hpdev->init_callbacks, cb); - } -} - -static void execute_callbacks(struct pico_hotplug_device *hpdev, int new_state, int event) -{ - struct pico_tree_node *cb_node = NULL, *cb_safe = NULL; - void (*cb)(struct pico_device *dev, int event); - if (new_state != hpdev->prev_state) - { - /* 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; - } -} - -static void timer_cb(__attribute__((unused)) pico_time t, __attribute__((unused)) void*v) -{ - struct pico_tree_node *node = NULL, *safe = NULL; - int new_state, event; - struct pico_hotplug_device *hpdev = NULL; - - /* 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 == 1) { - event = PICO_HOTPLUG_EVENT_UP; - } else { - event = PICO_HOTPLUG_EVENT_DOWN; - } - - initial_callbacks(hpdev, event); - execute_callbacks(hpdev, new_state, event); - } - - timer_id = pico_timer_add(PICO_HOTPLUG_INTERVAL, &timer_cb, NULL); - if (timer_id == 0) { - dbg("HOTPLUG: Failed to start timer\n"); - } -} - -static int ensure_hotplug_timer(void) -{ - if (timer_id == 0) - { - timer_id = pico_timer_add(PICO_HOTPLUG_INTERVAL, &timer_cb, NULL); - if (timer_id == 0) { - dbg("HOTPLUG: Failed to start timer\n"); - return -1; - } - } - - return 0; -} - -static void disable_hotplug_timer(void) -{ - if (timer_id != 0) - { - pico_timer_cancel(timer_id); - timer_id = 0; - } -} - -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 it does not have a link_state, */ - /* the device does not support hotplug detection */ - 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; - hotplug_dev->init_callbacks.root = &LEAF; - hotplug_dev->init_callbacks.compare = &callback_compare; - if (pico_tree_insert(&Hotplug_device_tree, hotplug_dev)) { - PICO_FREE(hotplug_dev); - return -1; - } - } - - if (pico_tree_insert(&(hotplug_dev->callbacks), cb) == &LEAF) { - PICO_FREE(hotplug_dev); - return -1; - } - - if (pico_tree_insert(&(hotplug_dev->init_callbacks), cb) == &LEAF) { - pico_tree_delete(&(hotplug_dev->callbacks), cb); - PICO_FREE(hotplug_dev); - return -1; - } - - if (ensure_hotplug_timer() < 0) { - pico_hotplug_deregister((struct pico_device *)hotplug_dev, cb); - return -1; - } - - 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); - pico_tree_delete(&hotplug_dev->init_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)) - { - disable_hotplug_timer(); - } - - 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 1ab7d85..0000000 --- a/ext/picotcp/modules/pico_hotplug_detection.h +++ /dev/null @@ -1,23 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -/* register your callback to be notified of hotplug events on a certain device. - * Note that each callback will be called at least once, shortly after adding, for initialization. - */ -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 3a8ae17..0000000 --- a/ext/picotcp/modules/pico_icmp4.c +++ /dev/null @@ -1,434 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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; - - if (f == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - 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); - } - - reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, f->dev, (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); -} - -static PICO_TREE_DECLARE(Pings, cookie_compare); - -static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie) -{ - struct pico_frame *echo = NULL; - struct pico_icmp4_hdr *hdr; - struct pico_device *dev = pico_ipv4_source_dev_find(&cookie->dst); - if (!dev) - return -1; - - echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size)); - 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 int send_ping(struct pico_icmp4_ping_cookie *cookie) -{ - uint32_t timeout_timer = 0; - struct pico_icmp4_stats stats; - pico_icmp4_send_echo(cookie); - cookie->timestamp = pico_tick; - timeout_timer = pico_timer_add((uint32_t)cookie->timeout, ping_timeout, cookie); - if (!timeout_timer) { - goto fail; - } - if (cookie->seq < (uint16_t)cookie->count) { - if (!pico_timer_add((uint32_t)cookie->interval, next_ping, cookie)) { - pico_timer_cancel(timeout_timer); - goto fail; - } - } - return 0; - -fail: - dbg("ICMP4: Failed to start timer\n"); - cookie->err = PICO_PING_ERR_ABORTED; - stats.err = cookie->err; - cookie->cb(&stats); - pico_tree_delete(&Pings, cookie); - - return -1; -} - -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++; - - if (pico_tree_insert(&Pings, newcookie)) { - dbg("ICMP4: Failed to insert new cookie in tree \n"); - PICO_FREE(newcookie); - return; - } - - if (send_ping(newcookie)) { - dbg("ICMP4: Failed to send ping\n"); - PICO_FREE(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; - - if (pico_tree_insert(&Pings, cookie)) { - dbg("ICMP4: Failed to insert cookie in tree \n"); - PICO_FREE(cookie); - return -1; - } - - if (send_ping(cookie)) { - PICO_FREE(cookie); - return -1; - } - - 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 7a3a5e8..0000000 --- a/ext/picotcp/modules/pico_icmp4.h +++ /dev/null @@ -1,162 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 fdf6a98..0000000 --- a/ext/picotcp/modules/pico_icmp6.c +++ /dev/null @@ -1,901 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Authors: Kristof Roelants, Daniele Lacamera - *********************************************************************/ - -#include "pico_config.h" -#include "pico_icmp6.h" -#include "pico_ipv6_nd.h" -#include "pico_6lowpan.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" - -#ifdef DEBUG_ICMP6 - #define icmp6_dbg dbg -#else - #define icmp6_dbg(...) do { } while(0) -#endif - -static struct pico_queue icmp6_in; -static struct pico_queue icmp6_out; - -/****************************************************************************** - * Function prototypes - ******************************************************************************/ - -#ifdef PICO_SUPPORT_6LOWPAN -static int pico_6lp_nd_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *tgt, uint8_t type, struct pico_ip6 *dst); -#endif - -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, echo->dev, (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; - - 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; -#if defined(PICO_SUPPORT_MCAST) && defined(PICO_SUPPORT_MLD) - 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, f->dev, (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, f->dev, (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, f->dev, (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); - /* 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); -} - -/* Provide a Link-Layer Address Option, either Source (SLLAO) or Destination (DLLAO) */ -static int pico_icmp6_provide_llao(struct pico_icmp6_opt_lladdr *llao, uint8_t type, struct pico_device *dev, struct pico_ip6 *src) -{ -#ifdef PICO_SUPPORT_6LOWPAN - struct pico_6lowpan_info *info = (struct pico_6lowpan_info *)dev->eth; -#endif - IGNORE_PARAMETER(src); - llao->type = type; - - if (!dev->mode && dev->eth) { - memcpy(llao->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH); - llao->len = 1; - } -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(dev) && dev->eth) { - if (src && IID_16(&src->addr[8])) { - memcpy(llao->addr.pan.data, (uint8_t *)&info->addr_short.addr, SIZE_6LOWPAN_SHORT); - memset(llao->addr.pan.data + SIZE_6LOWPAN_SHORT, 0, 4); - llao->len = 1; - } else { - memcpy(llao->addr.pan.data, info->addr_ext.addr, SIZE_6LOWPAN_EXT); - memset(llao->addr.pan.data + SIZE_6LOWPAN_EXT, 0, 6); - llao->len = 2; - } - } -#endif - else { - return -1; - } - - return 0; -} - -/* Prepares a ICMP6 neighbor solicitation message */ -static struct pico_frame *pico_icmp6_neigh_sol_prep(struct pico_device *dev, struct pico_ip6 *dst, uint16_t len) -{ - struct pico_icmp6_hdr *icmp = NULL; - struct pico_frame *sol = NULL; - IGNORE_PARAMETER(dev); - - /* Create pico_frame to contain the Neighbor Solicitation */ - sol = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, len); - if (!sol) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - sol->payload = sol->transport_hdr + len; - sol->payload_len = 0; - icmp = (struct pico_icmp6_hdr *)sol->transport_hdr; - icmp->type = PICO_ICMP6_NEIGH_SOL; - icmp->code = 0; - icmp->msg.info.neigh_sol.unused = 0; - icmp->msg.info.neigh_sol.target = *dst; - return sol; -} - -/* RFC 4861 $7.2.2: sending neighbor solicitations */ -int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *tgt, uint8_t type, struct pico_ip6 *dst) -{ - struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }}; - struct pico_icmp6_opt_lladdr *llao = NULL; - struct pico_icmp6_hdr *icmp = NULL; - struct pico_frame *sol = NULL; - uint8_t i = 0; - uint16_t len = 0; -#ifndef PICO_SUPPORT_6LOWPAN - IGNORE_PARAMETER(dst); -#endif - - if (pico_ipv6_is_multicast(tgt->addr)) { - return -1; - } -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(dev)) { - return pico_6lp_nd_neighbor_solicitation(dev, tgt, type, dst); - } -#endif - else { - /* Determine the size frame needs to be for the Neighbor Solicitation */ - len = PICO_ICMP6HDR_NEIGH_SOL_SIZE; - if (PICO_ICMP6_ND_DAD != type) - len = (uint16_t)(len + 8); - - /* Prepare a neighbor solicitation message */ - sol = pico_icmp6_neigh_sol_prep(dev, tgt, len); - if (sol) { - icmp = (struct pico_icmp6_hdr *)sol->transport_hdr; - - /* Provide SLLAO if it's neighbor solicitation for DAD */ - llao = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s)); - if (PICO_ICMP6_ND_DAD != type && pico_icmp6_provide_llao(llao, PICO_ND_OPT_LLADDR_SRC, dev, NULL)) { - pico_frame_discard(sol); - return -1; - } else { - /* Determine destination address */ - if (type == PICO_ICMP6_ND_SOLICITED || type == PICO_ICMP6_ND_DAD) { - for (i = 1; i <= 3; ++i) - daddr.addr[PICO_SIZE_IP6 - i] = tgt->addr[PICO_SIZE_IP6 - i]; - } else { - daddr = *tgt; - } - - 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; - } - } - } - return -1; -} - -#ifdef PICO_SUPPORT_6LOWPAN -/* Provide an Address Registration Option */ -static void pico_6lp_nd_provide_aro(struct pico_icmp6_opt_aro *aro, struct pico_device *dev, uint8_t type) -{ - struct pico_6lowpan_info *info = (struct pico_6lowpan_info *)dev->eth; - aro->type = PICO_ND_OPT_ARO; - aro->len = 2; - aro->status = 0; - if (PICO_ICMP6_ND_DEREGISTER == type) - aro->lifetime = 0; - else - aro->lifetime = short_be(PICO_6LP_ND_DEFAULT_LIFETIME); - memcpy(aro->eui64.addr, info->addr_ext.addr, SIZE_6LOWPAN_EXT); -} - -/* Send an ICMP6 neighbor solicitation according to RFC6775 */ -static int pico_6lp_nd_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *tgt, uint8_t type, struct pico_ip6 *dst) -{ - uint32_t llao_len = IID_16(&tgt->addr[8]) ? 8 : 16; - struct pico_icmp6_opt_lladdr *llao = NULL; - struct pico_icmp6_opt_aro *aro = NULL; - struct pico_icmp6_hdr *icmp = NULL; - struct pico_frame *sol = NULL; - uint16_t len = 0; - - /* Determine the size frame needs to be for the Neighbor Solicitation */ - len = (uint16_t)(PICO_ICMP6HDR_NEIGH_SOL_SIZE + llao_len); - if (PICO_ICMP6_ND_DAD == type) - len = (uint16_t)(len + sizeof(struct pico_icmp6_opt_aro)); - - /* Prepare a neighbor solicitation message */ - sol = pico_icmp6_neigh_sol_prep(dev, tgt, len); - if (sol) { - icmp = (struct pico_icmp6_hdr *)sol->transport_hdr; - - /* Provide SLLAO if it's a neighbor solicitation for address registration */ - llao = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s)); - if (pico_icmp6_provide_llao(llao, PICO_ND_OPT_LLADDR_SRC, dev, NULL)) { - pico_frame_discard(sol); - return -1; - } else { - /* Provide ARO when it's a neighbor solicitation for address registration or re-registration */ - aro = (struct pico_icmp6_opt_aro *)(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s) + llao_len); - pico_6lp_nd_provide_aro(aro, dev, type); - - /* RFC6775: The address that is to be registered MUST be the IPv6 source address of the - * NS message. */ - sol->dev = dev; - pico_ipv6_frame_push(sol, tgt, dst, PICO_PROTO_ICMP6, (type == PICO_ICMP6_ND_DAD)); - return 0; - } - } - return -1; -} -#endif - -/* 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, f->dev, 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); - - /* 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_ip6 *dst) -{ - struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}; - struct pico_icmp6_opt_lladdr *lladdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_frame *sol = NULL; - uint16_t len = 0; - - len = PICO_ICMP6HDR_ROUTER_SOL_SIZE; - if (!pico_ipv6_is_unspecified(src->addr)) { - len = (uint16_t)(len + 8); -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(dev)) - len = (uint16_t)(len + 8); - } else if (PICO_DEV_IS_6LOWPAN(dev) && pico_ipv6_is_unspecified(src->addr)) { - return -1; /* RFC6775 (6LoWPAN): An unspecified source address MUST NOT be used in RS messages. */ -#endif - } - - sol = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, 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)); - if (pico_icmp6_provide_llao(lladdr, PICO_ND_OPT_LLADDR_SRC, dev, NULL)) { - pico_frame_discard(sol); - return -1; - } - } - - sol->dev = dev; - - if (!dev->mode) { - /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, 0); - } -#ifdef PICO_SUPPORT_6LOWPAN - else { - if (dst) - daddr = *dst; - /* Force this frame to be send with the EUI-64-address */ - pico_ipv6_frame_push(sol, src, &daddr, PICO_PROTO_ICMP6, 0); - } -#else - IGNORE_PARAMETER(dst); -#endif - return 0; -} - -#define PICO_RADV_VAL_LIFETIME (long_be(86400)) -#define PICO_RADV_PREF_LIFETIME (long_be(14400)) - -static struct pico_ip6 pico_icmp6_address_to_prefix(struct pico_ip6 addr, struct pico_ip6 nm) -{ - struct pico_ip6 prefix; - uint8_t i = 0; - - for (i = 0; i < PICO_SIZE_IP6; i++) { - prefix.addr[i] = (uint8_t)(addr.addr[i] & nm.addr[i]); - } - - return prefix; -} - -/* 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_ip6 prefix_addr = {{ 0x00 }}; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_icmp6_opt_lladdr *lladdr; - struct pico_icmp6_opt_prefix *prefix; - struct pico_ipv6_link *global = NULL; - uint16_t len = 0; - 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, dev, len); - if (!adv) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - adv->payload = adv->transport_hdr + len; - adv->payload_len = 0; - - 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; - /* Find the globally routable prefix of the router-interface */ - if ((global = pico_ipv6_global_get(dev))) { - prefix_addr = pico_icmp6_address_to_prefix(global->address, global->netmask); - memcpy(&prefix->prefix, &prefix_addr, 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; - - if (!dev->mode && dev->eth) { - lladdr->len = 1; - memcpy(lladdr->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH); - } else { - - return -1; - } - - 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, 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); -} -static 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, cookie->dev, (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)); - 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 int pico_icmp6_send_ping(struct pico_icmp6_ping_cookie *cookie) -{ - uint32_t interval_timer = 0; - struct pico_icmp6_stats stats; - pico_icmp6_send_echo(cookie); - cookie->timestamp = pico_tick; - interval_timer = pico_timer_add((pico_time)(cookie->interval), pico_icmp6_next_ping, cookie); - if (!interval_timer) { - goto fail; - } - if (!pico_timer_add((pico_time)(cookie->timeout), pico_icmp6_ping_timeout, cookie)) { - pico_timer_cancel(interval_timer); - goto fail; - } - return 0; - -fail: - dbg("ICMP6: Failed to start timer\n"); - cookie->err = PICO_PING6_ERR_ABORTED; - stats.err = cookie->err; - cookie->cb(&stats); - pico_tree_delete(&IPV6Pings, cookie); - - return -1; -} - -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++; - - if (pico_tree_insert(&IPV6Pings, new)) { - dbg("ICMP6: Failed to insert new cookie in tree\n"); - PICO_FREE(new); - return; - } - - if (pico_icmp6_send_ping(new)) { - dbg("ICMP6: Failed to send ping\n"); - PICO_FREE(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; - - if (pico_tree_insert(&IPV6Pings, cookie)) { - dbg("ICMP6: Failed to insert cookie in tree\n"); - PICO_FREE(cookie); - return -1; - } - - if (pico_icmp6_send_ping(cookie)) { - PICO_FREE(cookie); - return -1; - } - 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 b449075..0000000 --- a/ext/picotcp/modules/pico_icmp6.h +++ /dev/null @@ -1,326 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_SOL_SIZE_6LP 16 -#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 */ -#define PICO_ND_OPT_ARO 33 /* RFC 6775 */ -#define PICO_ND_OPT_6CO 34 /* RFC 6775 */ -#define PICO_ND_OPT_ABRO 35 /* RFC 6775 */ - -/* 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_ND_DEREGISTER 4 - -#define PICO_ICMP6_MAX_RTR_SOL_DELAY 1000 - -#define PICO_ICMP6_OPT_LLADDR_SIZE (8) - -/****************************************************************************** - * 6LoWPAN Constants - ******************************************************************************/ - -/* Address registration lifetime */ -#define PICO_6LP_ND_DEFAULT_LIFETIME (120) /* TWO HOURS */ - -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[1]; - } mld; - /* 6LoWPAN Duplicate Address Message */ - PEDANTIC_STRUCT_DEF da_s { - uint8_t status; - uint8_t reserved; - uint16_t lifetime; - struct pico_6lowpan_ext eui64; - struct pico_ip6 addr; - } da; - } info; - } msg; -}; - -PACKED_UNION_DEF pico_hw_addr { - struct pico_eth mac; -#ifdef PICO_SUPPORT_6LOWPAN - union pico_6lowpan_u pan; -#endif /* PICO_SUPPORT_6LOWPAN */ - uint8_t data[8]; -}; - -/****************************************************************************** - * ICMP6 Neighbor Discovery Options - ******************************************************************************/ - -PACKED_STRUCT_DEF pico_icmp6_opt_lladdr -{ - uint8_t type; - uint8_t len; - union pico_hw_addr 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; -}; - -/* 6LoWPAN Address Registration Option (ARO) */ -PACKED_STRUCT_DEF pico_icmp6_opt_aro -{ - uint8_t type; - uint8_t len; - uint8_t status; - uint8_t res0; - uint16_t res1; - uint16_t lifetime; - struct pico_6lowpan_ext eui64; -}; - -#define ICMP6_ARO_SUCCES (0u) -#define ICMP6_ARO_DUP (1u) -#define ICMP6_ARO_FULL (2u) - -/* 6LoWPAN Context Option (6CO) */ -PACKED_STRUCT_DEF pico_icmp6_opt_6co -{ - uint8_t type; - uint8_t len; - uint8_t clen; - uint8_t id: 4; - uint8_t res: 3; - uint8_t c: 1; - uint16_t lifetime; - uint8_t prefix; -}; - -/* 6LoWPAN Authoritative Border Router Option (ABRO) */ -PACKED_STRUCT_DEF pico_icmp6_opt_abro -{ - uint8_t type; - uint8_t len; - uint16_t version_low; - uint16_t version_high; - uint16_t lifetime; - struct pico_ip6 addr; -}; - -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 *tgt, uint8_t type, struct pico_ip6 *dst); -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, struct pico_ip6 *dst); - -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 49f8358..0000000 --- a/ext/picotcp/modules/pico_igmp.c +++ /dev/null @@ -1,1170 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" -#include "pico_mcast.h" - -#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST) - -#ifdef DEBUG_IGMP - #define igmp_dbg dbg -#else - #define igmp_dbg(...) do {} while(0) -#endif - -/* 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_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 mcast_parameters *p); - -/* state callback prototype */ -typedef int (*callback)(struct mcast_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); - -} -static PICO_TREE_DECLARE(IGMPTimers, igmp_timer_cmp); - -static inline int igmpparm_group_compare(struct mcast_parameters *a, struct mcast_parameters *b) -{ - return pico_ipv4_compare(&a->mcast_group.ip4, &b->mcast_group.ip4); -} - -static inline int igmpparm_link_compare(struct mcast_parameters *a, struct mcast_parameters *b) -{ - return pico_ipv4_compare(&a->mcast_link.ip4, &b->mcast_link.ip4); -} - -static int igmp_parameters_cmp(void *ka, void *kb) -{ - struct mcast_parameters *a = ka, *b = kb; - int cmp = igmpparm_group_compare(a, b); - if (cmp) - return cmp; - - return igmpparm_link_compare(a, b); -} -static 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); -} -static PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp); -static PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp); - -static struct mcast_parameters *pico_igmp_find_parameter(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) -{ - struct mcast_parameters test = { - 0 - }; - if (!mcast_link || !mcast_group) - return NULL; - - test.mcast_link.ip4 = *mcast_link; - test.mcast_group.ip4 = *mcast_group; - return pico_tree_findKey(&IGMPParameters, &test); -} - -static int pico_igmp_delete_parameter(struct mcast_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()); - if (!pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_igmp_timer_expired, timer)) { - igmp_dbg("IGMP: Failed to start expiration timer\n"); - pico_tree_delete(&IGMPTimers, timer); - PICO_FREE(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(); - - if (pico_tree_insert(&IGMPTimers, timer)) { - igmp_dbg("IGMP: Failed to insert timer in tree\n"); - PICO_FREE(timer); - return -1; - } - - if (!pico_timer_add(timer->delay, &pico_igmp_timer_expired, timer)) { - igmp_dbg("IGMP: Failed to start expiration timer\n"); - pico_tree_delete(&IGMPTimers, timer); - PICO_FREE(timer); - return -1; - } - 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 mcast_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; - struct igmp_message *message = NULL; - struct mcast_parameters *p = NULL; - struct pico_ip4 mcast_group = { - 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; - /* Check if max_resp_time is set RFC 3376 $7.1 */ - 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; - /* Reset the event and state to prevent deadlock */ - message = (struct igmp_message *)f->transport_hdr; - mcast_group.addr = message->mcast_group; - p = pico_igmp_find_parameter(&link->address, &mcast_group); - if(p) { - p->state = IGMP_STATE_NON_MEMBER; - p->event = IGMP_EVENT_CREATE_GROUP; - } - - 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! */ - if (pico_igmp_timer_start(&t) < 0) - return -1; - } else { - /* IGMPv1 query, not supported */ - return -1; - } - } else { - /* invalid query, silently ignored */ - return -1; - } - - return 0; -} - -static struct mcast_parameters *pico_igmp_analyse_packet(struct pico_frame *f) -{ - struct igmp_message *message = NULL; - struct mcast_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 mcast_parameters)); - if (!p) - return NULL; - - p->state = IGMP_STATE_NON_MEMBER; - p->mcast_link.ip4 = link->address; - p->mcast_group.ip4 = mcast_group; - if (pico_tree_insert(&IGMPParameters, p)) { - igmp_dbg("IGMP: Failed to insert parameters in tree\n"); - PICO_FREE(p); - return NULL; - } - } 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 mcast_parameters *p = NULL; - IGNORE_PARAMETER(self); - - if (!pico_igmp_is_checksum_valid(f)) - goto out; - - p = pico_igmp_analyse_packet(f); - if (!p) - goto out; - - if (pico_igmp_compatibility_mode(f) < 0) - 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 mcast_parameters *p = NULL; - - if (!mcast_link || !mcast_group) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - 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 mcast_parameters)); - if (!p) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - p->state = IGMP_STATE_NON_MEMBER; - p->mcast_link.ip4 = *mcast_link; - p->mcast_group.ip4 = *mcast_group; - if (pico_tree_insert(&IGMPParameters, p)) { - igmp_dbg("IGMP: Failed to insert parameters in tree\n"); - PICO_FREE(p); - return -1; - } - - } 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 mcast_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((struct pico_ip4*)&p->mcast_link); - if (!link) - return -1; - - mcast_group = p->mcast_group.ip4; - 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_igmpv3_generate_filter(struct mcast_filter_parameters *filter, struct mcast_parameters *p) -{ - struct pico_mcast_group *g = NULL, test = { - 0 - }; - struct pico_tree *IGMPFilter = NULL; - struct pico_ipv4_link *link = (struct pico_ipv4_link*) filter->link; - filter->p = (struct mcast_parameters *)p; - filter->allow = &IGMPAllow; - filter->block = &IGMPBlock; - filter->filter = IGMPFilter; - filter->sources = 0; - filter->proto = PICO_IGMPV3; - test.mcast_addr = p->mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - filter->g = (struct pico_mcast_group *)g; - return pico_mcast_generate_filter(filter, p); -} -static int8_t pico_igmpv3_generate_report(struct mcast_filter_parameters *filter, struct mcast_parameters *p) -{ - struct igmpv3_report *report = NULL; - struct igmpv3_group_record *record = NULL; - struct pico_tree_node *index = NULL; - struct pico_device *dev = NULL; - uint16_t len = 0; - uint16_t i = 0; - len = (uint16_t)(sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (filter->sources * sizeof(struct pico_ip4))); - dev = pico_ipv4_link_find((struct pico_ip4 *)&p->mcast_link); - p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, (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->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 = filter->record_type; - record->aux = 0; - record->sources = short_be(filter->sources); - record->mcast_group = p->mcast_group.ip4.addr; - if (filter->filter && !pico_tree_empty(filter->filter)) { - uint32_t *source_addr = (uint32_t *)((uint8_t *)record + sizeof(struct igmpv3_group_record)); - i = 0; - pico_tree_foreach(index, filter->filter) - { - source_addr[i] = ((struct pico_ip4 *)index->keyValue)->addr; - i++; - } - } - - if(i != filter->sources) { - return -1; - } - - report->crc = short_be(pico_checksum(report, len)); - return 0; -} -static int8_t pico_igmpv2_generate_report(struct mcast_parameters *p) -{ - struct igmp_message *report = NULL; - uint8_t report_type = IGMP_TYPE_MEM_REPORT_V2; - struct pico_device *dev = NULL; - if (p->event == IGMP_EVENT_DELETE_GROUP) - report_type = IGMP_TYPE_LEAVE_GROUP; - - dev = pico_ipv4_link_find((struct pico_ip4 *)&p->mcast_link); - p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, 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->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.ip4.addr; - - report->crc = 0; - report->crc = short_be(pico_checksum(report, sizeof(struct igmp_message))); - return 0; -} -static int8_t pico_igmp_generate_report(struct mcast_parameters *p) -{ - struct mcast_filter_parameters filter; - int8_t result; - - filter.link = (union pico_link *)pico_ipv4_link_get((struct pico_ip4 *) &p->mcast_link); - if (!filter.link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (filter.link->ipv4.mcast_compatibility) { - case PICO_IGMPV1: - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - - case PICO_IGMPV2: - { - return pico_igmpv2_generate_report(p); - } - case PICO_IGMPV3: - { - result = pico_igmpv3_generate_filter(&filter, p); - if(result < 0) - return -1; - - if(result != MCAST_NO_REPORT) - return pico_igmpv3_generate_report(&filter, p); - } - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - -/* stop timer, send leave if flag set */ -static int stslifs(struct mcast_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.ip4; - t.mcast_group = p->mcast_group.ip4; - if (pico_igmp_timer_stop(&t) < 0) - return -1; - - if(pico_igmp_generate_report(p) < 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 mcast_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.ip4; - t.mcast_group = p->mcast_group.ip4; - t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - if (pico_igmp_timer_start(&t) < 0) - return -1; - - 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 mcast_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((struct pico_ip4 *)&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.ip4, &p->mcast_group.ip4); - 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 mcast_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.ip4); - 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.ip4; - t.mcast_group = p->mcast_group.ip4; - t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - if (pico_igmp_timer_start(&t) < 0) - return -1; - - 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 mcast_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_generate_report(p) < 0) - return -1; - 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 mcast_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.ip4; - t.mcast_group = p->mcast_group.ip4; - t.delay = (pico_rand() % ((1u + p->max_resp_time) * 100u)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - if (pico_igmp_timer_start(&t) < 0) - return -1; - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* stop timer, clear flag */ -static int stcl(struct mcast_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.ip4; - t.mcast_group = p->mcast_group.ip4; - 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 mcast_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 mcast_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.ip4, &p->mcast_group.ip4); - 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 mcast_parameters *p) -{ - igmp_dbg("IGMP: ignore and discard frame\n"); - pico_frame_discard(p->f); - return 0; -} - -/* finite state machine table */ -static 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 mcast_parameters *p) -{ - struct pico_tree_node *index = NULL; - struct mcast_parameters *_p = NULL; - - igmp_dbg("IGMP: process event on group address %08X\n", p->mcast_group.ip4.addr); - if (p->event == IGMP_EVENT_QUERY_RECV && p->mcast_group.ip4.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.ip4.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 58aa6a9..0000000 --- a/ext/picotcp/modules/pico_igmp.h +++ /dev/null @@ -1,26 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 e28775e..0000000 --- a/ext/picotcp/modules/pico_ipfilter.c +++ /dev/null @@ -1,464 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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) - -#ifdef DEBUG_IPF - #define ipf_dbg dbg -#else - #define ipf_dbg(...) do {} while(0) -#endif - -/**************** 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); -}; - -static 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->code == 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 c966b28..0000000 --- a/ext/picotcp/modules/pico_ipfilter.h +++ /dev/null @@ -1,29 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 74739a1..0000000 --- a/ext/picotcp/modules/pico_ipv4.c +++ /dev/null @@ -1,1660 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" -#include "pico_ethernet.h" -#include "pico_mcast.h" - -#include "../../../include/libztDebug.h" - -#ifdef PICO_SUPPORT_IPV4 - -#ifdef PICO_SUPPORT_MCAST - -#ifdef DEBUG_MCAST -#define ip_mcast_dbg dbg -#else -#define ip_mcast_dbg(...) do {} while(0) -#endif - -# 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 - -/* 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, struct pico_device *dev, 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; - -} - -extern 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; -} - -static 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); - - if (!hdr) - return -1; - - (void)self; - - /* 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 defined(PICO_SUPPORT_IPV4FRAG) || defined(PICO_SUPPORT_IPV6FRAG) - f->frag = short_be(hdr->frag); -#endif - - 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 defined(PICO_SUPPORT_IPV4FRAG) || defined(PICO_SUPPORT_IPV6FRAG) - if (f->frag & PICO_IPV4_EVIL) { - (void)pico_icmp4_param_problem(f, 0); - pico_frame_discard(f); /* RFC 3514 */ - return 0; - } -#endif - - 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 defined(PICO_SUPPORT_IPV4FRAG) || defined(PICO_SUPPORT_IPV6FRAG) - if (f->frag & (PICO_IPV4_MOREFRAG | PICO_IPV4_FRAG_MASK)) - { -#ifdef PICO_SUPPORT_IPV4FRAG - pico_ipv4_process_frag(hdr, f, hdr->proto); - /* Frame can be discarded, frag will handle its own copy */ -#endif - /* We do not support fragmentation, discard quietly */ - pico_frame_discard(f); - return 0; - } -#endif - - 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_datalink_send(f); -} - - -static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, struct pico_device *dev, uint16_t size) -{ - struct pico_frame *f = NULL; - IGNORE_PARAMETER(self); - - f = pico_proto_ethernet.alloc(&pico_proto_ethernet, dev, (uint16_t)(size + PICO_SIZE_IP4HDR)); - /* TODO: In 6LoWPAN topic branch update to make use of dev->ll_mode */ - - if (!f) - return NULL; - - f->net_len = PICO_SIZE_IP4HDR; - f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR; - f->transport_len = (uint16_t)size; - - /* Datalink size is accounted for in pico_datalink_send (link layer) */ - f->len = (uint32_t)(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_ANY) { - return NULL; - } - - 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; -#endif - - if (!dst) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - -#ifdef PICO_SUPPORT_AODV - node_address.ip4.addr = dst->addr; - if (dst->addr && pico_ipv4_is_unicast(dst->addr)) - pico_aodv_lookup(&node_address); - -#endif - - 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.ip4, &b->mcast_addr.ip4); -} - -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.ip4.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; - if (pico_tree_insert(&g->MCASTSources, source)) { - dbg("IPv4: Failed to insert source in tree\n"); - PICO_FREE(source); - return -1; - } - } - } - } - - 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.ip4 = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (reference_count) - g->reference_count++; - -#ifdef PICO_SUPPORT_IGMP - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); -#endif - } 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.ip4 = *mcast_group; - g->MCASTSources.root = &LEAF; - g->MCASTSources.compare = ipv4_mcast_sources_cmp; - if (pico_tree_insert(link->MCASTGroups, g)) { - dbg("IPv4: Failed to insert group in tree\n"); - PICO_FREE(g); - return -1; - } - -#ifdef PICO_SUPPORT_IGMP - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE); -#endif - } - - 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.ip4 = *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)) { -#ifdef PICO_SUPPORT_IGMP - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE); -#endif - /* 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 { -#ifdef PICO_SUPPORT_IGMP - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); -#endif - 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.ip4 = 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) -{ - IGNORE_PARAMETER(mcast_link); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(reference_count); - IGNORE_PARAMETER(filter_mode); - IGNORE_PARAMETER(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) -{ - IGNORE_PARAMETER(mcast_link); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(reference_count); - IGNORE_PARAMETER(filter_mode); - IGNORE_PARAMETER(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 */ - int32_t retval = 0; - 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; - goto drop; - } - - - 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); - if (!cpy) { - pico_err = PICO_ERR_ENOMEM; - ip_mcast_dbg("MCAST: Failed to copy frame\n"); - goto drop; - } - - retval = pico_enqueue(&in, cpy); - if (retval <= 0) - pico_frame_discard(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 */ - retval = pico_enqueue(&in, f); - if (retval > 0) - return retval; - } else{ - /* TODO: Check if there are members subscribed here */ - retval = pico_enqueue(&out, f); - if (retval > 0) - return retval; - } - -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); -} - - -extern 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; - } - - if (pico_tree_insert(&Routes, new)) { - dbg("IPv4: Failed to insert route in tree\n"); - PICO_FREE(new); - return -1; - } - - 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; -} - - -extern 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 - - if (pico_tree_insert(&Tree_dev_link, new)) { - dbg("IPv4: Failed to insert link in tree\n"); -#ifdef PICO_SUPPORT_MCAST - PICO_FREE(new->MCASTGroups); -#endif - PICO_FREE(new); - return -1; - } - -#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); - DEBUG_EXTRA("Assigned ipv4 %s to device %s", 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, NULL, (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 { - /* No need to discard frame here, pico_ipv4_frame_push() already did that */ - 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_datalink_send(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 9a71c3f..0000000 --- a/ext/picotcp/modules/pico_ipv4.h +++ /dev/null @@ -1,122 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - *********************************************************************/ -#ifndef INCLUDE_PICO_IPV4 -#define INCLUDE_PICO_IPV4 -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_tree.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 -}; - - -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_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); - -#ifdef __cplusplus -extern "C" { -#endif -int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask); -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip); -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); -#ifdef __cplusplus -} -#endif - -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); -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 2970b8b..0000000 --- a/ext/picotcp/modules/pico_ipv6.c +++ /dev/null @@ -1,2141 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_ethernet.h" -#include "pico_6lowpan_ll.h" -#include "pico_mld.h" -#include "pico_mcast.h" -#ifdef PICO_SUPPORT_IPV6 - -#include "../../../include/libztDebug.h" - -#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 - -#ifdef DEBUG_IPV6 -#define ipv6_dbg dbg -#else -#define ipv6_dbg(...) do { } while(0) -#endif - -#ifdef PICO_SUPPORT_MCAST - -#ifdef DEBUG_MCAST -#define ipv6_mcast_dbg dbg -#else -#define ipv6_mcast_dbg(...) do { } while(0) -#endif - -static struct pico_ipv6_link *mcast_default_link_ipv6 = NULL; -#endif -/* 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); - -} - -static PICO_TREE_DECLARE(Tree_dev_ip6_link, ipv6_link_compare); -PICO_TREE_DECLARE(IPV6Routes, ipv6_route_compare); -static 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; -} - -extern 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_tree_node *index = NULL; - struct pico_ipv6_route *r = 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->mode == LL_MODE_ETHERNET && 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_datalink_send(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; -} - -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; - } - - 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; - } - -#else - IGNORE_PARAMETER(hbh); -#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_datalink_send(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, struct pico_device *dev, uint16_t size) -{ - struct pico_frame *f = NULL; - - IGNORE_PARAMETER(self); - - if (0) {} -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(dev)) { - f = pico_proto_6lowpan_ll.alloc(&pico_proto_6lowpan_ll, dev, (uint16_t)(size + PICO_SIZE_IP6HDR)); - } -#endif - else { -#ifdef PICO_SUPPORT_ETH - f = pico_proto_ethernet.alloc(&pico_proto_ethernet, dev, (uint16_t)(size + PICO_SIZE_IP6HDR)); -#else - f = pico_frame_alloc(size + PICO_SIZE_IP6HDR + PICO_SIZE_ETHHDR); -#endif - } - - if (!f) - return NULL; - - f->net_len = PICO_SIZE_IP6HDR; - f->transport_hdr = f->net_hdr + PICO_SIZE_IP6HDR; - f->transport_len = (uint16_t)size; - - /* Datalink size is accounted for in pico_datalink_send (link layer) */ - 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_mcast_group *a = ka, *b = kb; - return pico_ipv6_compare(&a->mcast_addr.ip6, &b->mcast_addr.ip6); -} -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_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_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); - if (pico_tree_insert(&g->MCASTSources, source)) { - ipv6_mcast_dbg("IPv6 MCAST: Failed to insert source in tree\n"); - PICO_FREE(source); - return -1; - } - } - } - } - 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_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.ip6 = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (reference_count) - g->reference_count++; - -#ifdef PICO_SUPPORT_MLD - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_UPDATE); -#endif - } 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.ip6 = *mcast_group; - g->MCASTSources.root = &LEAF; - g->MCASTSources.compare = ipv6_mcast_sources_cmp; - if (pico_tree_insert(link->MCASTGroups, g)) { - ipv6_mcast_dbg("IPv6 MCAST: Failed to insert group in tree\n"); - PICO_FREE(g); - return -1; - } - -#ifdef PICO_SUPPORT_MLD - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_CREATE); -#endif - } - - 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_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.ip6 = *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)) { -#ifdef PICO_SUPPORT_MLD - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_DELETE); -#endif - /* 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 { -#ifdef PICO_SUPPORT_MLD - res = pico_mld_state_change(mcast_link, mcast_group, filter_mode, _MCASTFilter, PICO_MLD_STATE_UPDATE); -#endif - 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_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.ip6 = 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) -{ - IGNORE_PARAMETER(mcast_link); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(reference_count); - IGNORE_PARAMETER(filter_mode); - IGNORE_PARAMETER(_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) -{ - IGNORE_PARAMETER(mcast_link); - IGNORE_PARAMETER(mcast_group); - IGNORE_PARAMETER(reference_count); - IGNORE_PARAMETER(filter_mode); - IGNORE_PARAMETER(_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) - { -#ifdef PICO_SUPPORT_MLD - 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; - } -#else - IGNORE_PARAMETER(hbh); -#endif - 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; - - /* RFC6775 $5.5.1: - * ... An unspecified source address MUST NOT be used in NS messages. - */ - if (f->dev->mode == LL_MODE_ETHERNET && (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 (dst && (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_IPV6_ROUTE -static void pico_ipv6_dbg_route(void) -{ - struct pico_ipv6_route *r; - struct pico_tree_node *index; - char ipv6_addr[PICO_IPV6_STRING]; - char netmask_addr[PICO_IPV6_STRING]; - char gateway_addr[PICO_IPV6_STRING]; - - pico_tree_foreach(index, &Routes){ - r = index->keyValue; - pico_ipv6_to_string(ipv6_addr, r->dest.addr); - pico_ipv6_to_string(netmask_addr, r->netmask.addr); - pico_ipv6_to_string(gateway_addr, r->gateway.addr); - dbg("Route to %s/%s, gw %s, dev: %s, metric: %d\n", ipv6_addr, netmask_addr, 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; -} - -struct pico_ipv6_route *pico_ipv6_gateway_by_dev(struct pico_device *dev) -{ - struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); - struct pico_ipv6_route *route = NULL; - struct pico_tree_node *node = NULL; - - /* Iterate over the IPv6-routes */ - pico_tree_foreach(node, &IPV6Routes) { - route = (struct pico_ipv6_route *)node->keyValue; - /* If the route is a default router, specified by the gw being set */ - if (!pico_ipv6_is_unspecified(route->gateway.addr) && pico_ipv6_is_unspecified(route->netmask.addr)) { - /* Iterate over device's links */ - while (link) { - /* If link is equal to route's link, router list is not empty */ - if (0 == ipv6_link_compare(link, route->link)) - return route; - link = pico_ipv6_link_by_dev_next(dev, link); - } - } - } - - return NULL; -} - -struct pico_ipv6_route *pico_ipv6_gateway_by_dev_next(struct pico_device *dev, struct pico_ipv6_route *last) -{ - struct pico_ipv6_link *link = NULL; - struct pico_ipv6_route *gw = NULL; - struct pico_tree_node *i = NULL; - int valid = 0; - - if (last == NULL) - valid = 1; - - pico_tree_foreach(i, &IPV6Routes) { - gw = (struct pico_ipv6_route *)i->keyValue; - /* If the route is a default router, specified by the gw being set */ - if (!pico_ipv6_is_unspecified(gw->gateway.addr) && pico_ipv6_is_unspecified(gw->netmask.addr)) { - /* Iterate over device's links */ - link = pico_ipv6_link_by_dev(dev); - while (link) { - /* If link is equal to route's link, routing list is not empty */ - if (0 == ipv6_link_compare(link, gw->link)) { - if (last == gw) { - valid = 1; - } else if (valid) { - return gw; - } - link = pico_ipv6_link_by_dev_next(dev, link); - } - } - } - } - return NULL; -} - -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)) { - /* Route already exists */ - 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; - } - - if (pico_tree_insert(&IPV6Routes, new)) { - ipv6_dbg("IPv6: Failed to insert route in tree\n"); - PICO_FREE(new); - return -1; - } - - 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); - if (!l->dad_timer) { - dbg("IPv6: Failed to start nd_dad timer\n"); - /* TODO does this have disastrous consequences? */ - } - return; - } - - if (l->isduplicate) { - DEBUG_ERROR("IPv6: duplicate address."); - 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) { - DEBUG_EXTRA("IPv6: DAD verified valid address."); - - l->istentative = 0; - } else { - /* Duplicate Address Detection */ - pico_icmp6_neighbor_solicitation(l->dev, &l->address, PICO_ICMP6_ND_DAD, NULL); - l->dad_timer = pico_timer_add(PICO_ICMP6_MAX_RTR_SOL_DELAY, pico_ipv6_nd_dad, &l->address); - if (!l->dad_timer) { - dbg("IPv6: Failed to start nd_dad timer\n"); - /* TODO does this have disastrous consequences? */ - } - } - } -} -#endif - -static struct pico_ipv6_link *pico_ipv6_do_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 }}; - 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; -#ifdef PICO_SUPPORT_MLD - new->mcast_compatibility = PICO_MLDV2; - new->mcast_last_query_interval = MLD_QUERY_INTERVAL; -#endif -#endif - if (pico_tree_insert(&IPV6Links, new)) { - ipv6_dbg("IPv6: Failed to insert link in tree\n"); -#ifdef PICO_SUPPORT_MCAST - PICO_FREE(new->MCASTGroups); -#endif - PICO_FREE(new); - return NULL; - } - 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); -#else - IGNORE_PARAMETER(all_hosts); -#endif - pico_ipv6_route_add(network, netmask, gateway, 1, new); -#ifdef PICO_SUPPORT_6LOWPAN - if (!PICO_DEV_IS_6LOWPAN(dev)) -#endif - pico_ipv6_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new); - /* XXX MUST join the all-nodes multicast address on that interface, as well as - * the solicited-node multicast address corresponding to each of the IP - * addresses assigned to the interface. (RFC 4861 $7.2.1) - * XXX RFC6775 (6LoWPAN): There is no need to join the solicited-node multicast address, since - * nobody multicasts NSs in this type of network. A host MUST join the all-nodes multicast - * address. */ -#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; -} - -struct pico_ipv6_link *pico_ipv6_link_add_no_dad(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask) -{ - struct pico_ipv6_link *new = pico_ipv6_do_link_add(dev, address, netmask); - if (new) { - new->istentative = 0; - } - return new; -} - -extern struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask) -{ -#ifdef DEBUG_IPV6 - char ipstr[40] = { - 0 - }; -#endif - /* Try to add the basic link */ - struct pico_ipv6_link *new = pico_ipv6_do_link_add(dev, address, netmask); - if (!new) - return NULL; - - /* Apply DAD */ - 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); - if (!new->dad_timer) { - dbg("IPv6: Failed to start nd_dad timer\n"); - pico_ipv6_link_del(dev, address); - return NULL; - } -#else - new->istentative = 0; -#endif - -#ifdef 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)) { - dbg("[0x%02X] - is global: %d - %d\n", link->address.addr[0], pico_ipv6_is_global(link->address.addr), link->address.addr[0] >> 0x05); - 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; -#ifdef PICO_SUPPORT_6LOWPAN - struct pico_ipv6_route *gw = NULL; -#endif - (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); - } -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(link->dev) && !pico_ipv6_is_linklocal(link->address.addr) && - (link->expire_time > 0) && (int)(link->expire_time - now) < (int)(TWO_HOURS >> 4)) { - /* RFC6775: The host SHOULD unicast one or more RSs to the router well before the - * shortest of the, Router Lifetime, PIO lifetimes and the lifetime of the 6COs. */ - while ((gw = pico_ipv6_gateway_by_dev_next(link->dev, gw))) { - pico_6lp_nd_start_soliciting(link, gw); - } - } -#endif - } - if (!pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL)) { - dbg("IPv6: Failed to start check_lifetime timer\n"); - /* TODO No more link lifetime checking now */ - } -} - -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 073c49f..0000000 --- a/ext/picotcp/modules/pico_ipv6.h +++ /dev/null @@ -1,189 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 */ -#define IPV6_OPTLEN(x) ((uint16_t)(((x + 1) << 3))) - -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; - uint8_t 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; - pico_time backoff; - uint8_t retrans; - 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_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); - -#ifdef __cplusplus -extern "C" { -#endif -struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask); -int pico_string_to_ipv6(const char *ipstr, uint8_t *ip); -#ifdef __cplusplus -} -#endif - -struct pico_ipv6_link *pico_ipv6_link_add_no_dad(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); -struct pico_ipv6_route *pico_ipv6_gateway_by_dev(struct pico_device *dev); -struct pico_ipv6_route *pico_ipv6_gateway_by_dev_next(struct pico_device *dev, struct pico_ipv6_route *last); -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 270cabd..0000000 --- a/ext/picotcp/modules/pico_ipv6_nd.c +++ /dev/null @@ -1,1586 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" -#include "pico_ethernet.h" -#include "pico_6lowpan.h" -#include "pico_6lowpan_ll.h" - -#ifdef PICO_SUPPORT_IPV6 - -#ifdef DEBUG_IPV6_ND -#define nd_dbg dbg -#else -#define nd_dbg(...) do {} while(0) -#endif - -#define ONE_MINUTE ((pico_time)(1000 * 60)) - -#ifdef PICO_SUPPORT_6LOWPAN - #define MAX_RTR_SOLICITATIONS (3) - #define RTR_SOLICITATION_INTERVAL (10000) - #define MAX_RTR_SOLICITATION_INTERVAL (60000) -#endif - -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; - union pico_hw_addr hwaddr; - struct pico_device *dev; - uint16_t is_router; - uint16_t failure_count; - pico_time expire; -}; - -/****************************************************************************** - * Function prototypes - ******************************************************************************/ - -#ifdef PICO_SUPPORT_6LOWPAN -static void pico_6lp_nd_deregister(struct pico_ipv6_link *); -static void pico_6lp_nd_unreachable_gateway(struct pico_ip6 *a); -static int pico_6lp_nd_neigh_adv_process(struct pico_frame *f); -static int neigh_sol_detect_dad_6lp(struct pico_frame *f); -#endif - -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) { - if (pico_datalink_send(f) <= 0) - pico_frame_discard(f); - 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); -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(l->dev)) { - pico_6lp_nd_deregister(l); - } -#endif - 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; - char address[120]; - /* Create a new NCE */ - n = PICO_ZALLOC(sizeof(struct pico_ipv6_neighbor)); - if (!n) - return NULL; - pico_ipv6_to_string(address, addr->addr); - memcpy(&n->address, addr, sizeof(struct pico_ip6)); - n->dev = dev; - - if (pico_tree_insert(&NCache, n)) { - nd_dbg("IPv6 ND: Failed to insert neigbor in tree\n"); - PICO_FREE(n); - return NULL; - } - - 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; -#ifdef PICO_SUPPORT_6LOWPAN - /* 6LP: Find any 6LoWPAN-hosts for which this address might have been a default gateway. - * If such a host found, send a router solicitation again */ - pico_6lp_nd_unreachable_gateway(a); -#endif /* PICO_SUPPORT_6LOWPAN */ - 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) { - return; - } else { - if (n->expire != (pico_time)0) { - return; - } else { - 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, &n->address); - } else { - pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_UNICAST, &n->address); - } - - 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; - } else { - if (n->state == PICO_ND_STATE_INCOMPLETE) { - return NULL; - } else 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->hwaddr.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 nd_options(uint8_t *options, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt, int optlen, int len) -{ - uint8_t type = 0; - int found = 0; - - while (optlen > 0) { - type = ((struct pico_icmp6_opt_lladdr *)options)->type; - len = ((struct pico_icmp6_opt_lladdr *)options)->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 *)options, sizeof(struct pico_icmp6_opt_lladdr)); - found++; - } - - if (optlen > 0) { - options += len << 3; - } else { /* parsing options: terminated. */ - return found; - } - } - return found; -} - -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. - * */ - struct pico_icmp6_hdr *icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - uint8_t *option = NULL; - int optlen = 0; - int len = 0; - - 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); - - return nd_options(option, opt, expected_opt, optlen, len); -} - -static size_t pico_hw_addr_len(struct pico_device *dev, struct pico_icmp6_opt_lladdr *opt) -{ - size_t len = PICO_SIZE_ETH; -#ifndef PICO_SUPPORT_6LOWPAN - IGNORE_PARAMETER(dev); - IGNORE_PARAMETER(opt); -#else - if (PICO_DEV_IS_6LOWPAN(dev)) { - if (1 == opt->len) { - len = (size_t)SIZE_6LOWPAN_SHORT; - } else { - len = (size_t)SIZE_6LOWPAN_EXT; - } - } -#endif - return len; -} - -static void pico_ipv6_neighbor_update(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) -{ - memcpy(n->hwaddr.data, opt->addr.data, pico_hw_addr_len(dev, opt)); -} - -static int pico_ipv6_neighbor_compare_stored(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) -{ - return memcmp(n->hwaddr.data, opt->addr.data, pico_hw_addr_len(dev, opt)); -} - -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, struct pico_device *dev) -{ - - if (IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt, dev) == 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, dev); - 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, dev) != 0)) { - pico_ipv6_neighbor_update(n, opt, dev); - 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, dev) != 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; - } else { - if (!(icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr)) - return; - else { - 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, f->dev); - - 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; - } - -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(f->dev)) { - /* 6LoWPAN: parse Address Registration Comfirmation(nothing on success, remove link on failure) */ - pico_6lp_nd_neigh_adv_process(f); - } -#endif - - /* Check if there's a NCE in the cache */ - 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, f->dev) == 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, f->dev); - 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) -{ - size_t len = pico_hw_addr_len(dev, opt); - struct pico_ipv6_neighbor *n = NULL; - n = pico_nd_add(ip, dev); - if (!n) - return NULL; - - memcpy(n->hwaddr.data, opt->addr.data, len); - memset(n->hwaddr.data + len, 0, sizeof(union pico_hw_addr) - len); - 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.data, n->hwaddr.data, pico_hw_addr_len(f->dev, &opt))) { - pico_ipv6_neighbor_update(n, &opt, f->dev); - 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_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_hdr *ipv6_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; - - if (!f->dev->mode) { - 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 (!f->dev->mode && !valid_lladdr && (0 == neigh_sol_detect_dad(f))) - return 0; -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(f->dev)) { - nd_dbg("[6LP-ND] Received Address Registration Option\n"); - neigh_sol_detect_dad_6lp(f); - } -#endif - - 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; - -#ifdef PICO_SUPPORT_6LOWPAN - /* Don't validate target address, the sol is always targeted at 6LBR so - * no possible interface on the 6LBR can have the same address as specified in - * the target */ - if (PICO_DEV_IS_6LOWPAN(f->dev)) - return 0; -#endif - - link = pico_ipv6_link_by_dev(f->dev); - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - while(link) { - /* RFC4861, 7.2.3: - * - * - The Target Address is a "valid" unicast or anycast address - * assigned to the receiving interface [ADDRCONF], - * - The Target Address is a unicast or anycast address for which the - * node is offering proxy service, or - * - The Target Address is a "tentative" address on which Duplicate - * Address Detection is being performed - */ - 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 (!f->dev->mode && 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); -} - -/*MARK*/ -#ifdef PICO_SUPPORT_6LOWPAN -static void pico_6lp_nd_unreachable_gateway(struct pico_ip6 *a) -{ - struct pico_ipv6_route *route = NULL; - struct pico_ipv6_link *local = NULL; - struct pico_tree_node *node = NULL; - struct pico_device *dev = NULL; - - /* RFC6775, 5.3: - * ... HOSTS need to intelligently retransmit RSs when one of its - * default routers becomes unreachable ... - */ - pico_tree_foreach(node, &Device_tree) { - if (PICO_DEV_IS_6LOWPAN(dev) && (!dev->hostvars.routing)) { - /* Check if there's a gateway configured */ - route = pico_ipv6_gateway_by_dev(dev); - while (route) { - if (0 == pico_ipv6_compare(&route->gateway, a)) { - local = pico_ipv6_linklocal_get(dev); - pico_6lp_nd_start_soliciting(local, route); - break; - } - route = pico_ipv6_gateway_by_dev_next(dev, route); - } - } - } -} - -static int pico_6lp_nd_validate_sol_aro(struct pico_icmp6_opt_aro *aro) -{ - if (aro->len != 2 || aro->status != 0) - return -1; - return 0; -} - -static int pico_6lp_nd_validate_adv_aro(struct pico_device *dev, struct pico_icmp6_opt_aro *aro, uint8_t *status) -{ - union pico_ll_addr addr, eui; - - /* RFC6775 - 5.5.2 : - * - If the length field is not two, the option is silently ignored. - * - If the EUI-64 field does not match the EUI-64 of the interface, - * the option is silently ignored. - */ - if (aro->len != 2) - return -1; - - /* TODO: Update to abstract address, e.g. remove dependency of '.pan' */ - eui.pan.addr._ext = aro->eui64; - eui.pan.mode = AM_6LOWPAN_EXT; - addr.pan.addr._ext = ((struct pico_6lowpan_info *)dev->eth)->addr_ext; - addr.pan.mode = AM_6LOWPAN_EXT; - - if (dev && pico_6lowpan_lls[dev->mode].addr_cmp) { - if (pico_6lowpan_lls[dev->mode].addr_cmp(&addr, &eui)) - return -1; - } else { - return -1; - } - - *status = aro->status; - return 0; -} - -/* Deregisters a link from all default gateways */ -static void pico_6lp_nd_deregister(struct pico_ipv6_link *l) -{ - struct pico_ipv6_route *gw = pico_ipv6_gateway_by_dev(l->dev); - while (gw) { - pico_icmp6_neighbor_solicitation(l->dev, &l->address, PICO_ICMP6_ND_DEREGISTER, &gw->gateway); - gw = pico_ipv6_gateway_by_dev_next(l->dev, gw); - } -} - -/* Retransmits neighbors solicitations with address registration if ARO is not acknowledged */ -static void pico_6lp_nd_register_try(pico_time now, void *arg) -{ - struct pico_ipv6_link *l = arg; - struct pico_ipv6_route *gw = pico_ipv6_gateway_by_dev(l->dev); - IGNORE_PARAMETER(now); - while (gw) { - l->istentative = 1; - pico_icmp6_neighbor_solicitation(l->dev, &l->address, PICO_ICMP6_ND_DAD, &gw->gateway); - gw = pico_ipv6_gateway_by_dev_next(l->dev, gw); - } - pico_timer_add(l->dev->hostvars.retranstime, pico_6lp_nd_register_try, l); -} - -/* Tries to register a link with one or more of its default routers */ -void pico_6lp_nd_register(struct pico_ipv6_link *link) -{ - /* RFC6775: When a host has configured a non-link-local IPv6 address, it registers that - * address with one or more of its default routers using the Address Registration - * Option (ARO) in an NS message. */ - pico_6lp_nd_register_try(PICO_TIME_MS(), link); -} - -/* Check if there are default routers configured. If not, sent a router solicitation */ -static void pico_6lp_nd_do_solicit(pico_time now, void *arg) -{ - struct pico_ipv6_route *gw = arg; - struct pico_ip6 *dst = NULL; - IGNORE_PARAMETER(now); - - if (!pico_ipv6_gateway_by_dev(gw->link->dev) && !gw->link->dev->hostvars.routing) { - /* If the solicitation is to be sent unicast */ - if (!pico_ipv6_is_unspecified(gw->gateway.addr) && gw->retrans < MAX_RTR_SOLICITATIONS) - dst = &gw->gateway; - - /* Exponential backoff */ - if (++gw->retrans == MAX_RTR_SOLICITATIONS) { - gw->backoff <<= 1; - if (gw->backoff >= MAX_RTR_SOLICITATION_INTERVAL) - gw->backoff = (pico_time)MAX_RTR_SOLICITATION_INTERVAL; - } - - /* If router list is empty, send router solicitation */ - pico_icmp6_router_solicitation(gw->link->dev, &gw->link->address, dst); - - /* Apply exponential retransmission timer, see RFC6775 5.3 */ - pico_timer_add(gw->backoff, pico_6lp_nd_do_solicit, gw); - nd_dbg("[6LP-ND]$ No default routers configured, soliciting\n"); - } else { - PICO_FREE(gw); - } -} - -/* Start transmitting repetitive router solicitations */ -int pico_6lp_nd_start_soliciting(struct pico_ipv6_link *l, struct pico_ipv6_route *gw) -{ - struct pico_ipv6_route *dummy = PICO_ZALLOC(sizeof(struct pico_ipv6_route)); - struct pico_ip6 *dst = NULL; - - if (dummy) { - if (gw) { // If the router solicitation has to be sent unicast ... - dst = &gw->gateway; // ... the gateway is the destination - memcpy(dummy->gateway.addr, gw->gateway.addr, PICO_SIZE_IP6); // and should be retrievable in the timer event - } - dummy->link = l; // the link that has to be reconfirmed as well. - - /* If router list is empty, send router solicitation */ - pico_icmp6_router_solicitation(l->dev, &l->address, dst); - - if (!l->dev->hostvars.routing) { - dummy->retrans = 0; - dummy->backoff = RTR_SOLICITATION_INTERVAL; - if (!pico_timer_add(dummy->backoff, pico_6lp_nd_do_solicit, dummy)) { - PICO_FREE(dummy); - return -1; - } - } else { - PICO_FREE(dummy); - } - return 0; - } - return -1; -} - -/* Validate Neighbor advertisement mesaage */ -static int pico_6lp_nd_neigh_adv_validate(struct pico_frame *f, uint8_t *status) -{ - struct pico_icmp6_hdr *icmp = (struct pico_icmp6_hdr *)f->transport_hdr; - struct pico_icmp6_opt_aro *aro = (struct pico_icmp6_opt_aro *)((uint8_t *)&icmp->msg.info.neigh_adv + sizeof(struct neigh_sol_s)); - struct pico_ipv6_hdr *ip = (struct pico_ipv6_hdr *)f->net_hdr; - - /* 6LP: Target address cannot be MCAST and the Source IP-address cannot be UNSPECIFIED or MCAST */ - if (pico_ipv6_is_multicast(icmp->msg.info.neigh_adv.target.addr) || pico_ipv6_is_unspecified(ip->src.addr) || - pico_ipv6_is_multicast(ip->src.addr)) - return -1; - - return pico_6lp_nd_validate_adv_aro(f->dev, aro, status); -} - -/* Process neighbor advertisement */ -static int pico_6lp_nd_neigh_adv_process(struct pico_frame *f) -{ - struct pico_icmp6_hdr *icmp = (struct pico_icmp6_hdr *)f->transport_hdr; - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - struct pico_ipv6_link *l = NULL; - struct pico_ip6 zero = { - .addr = {0} - }; - uint8_t status = 0; - - if (pico_6lp_nd_neigh_adv_validate(f, &status)) { - return -1; - } else { - l = pico_ipv6_link_get(&icmp->msg.info.neigh_adv.target); - if (l) - l->istentative = 0; - else - return -1; - - /* Globally routable address has been registered @ 6LoWPAN Border Router */ - if (1 == status) { // Duplicate address detected - nd_dbg("[6LP-ND]: Registering routable address failed, removing link...\n"); - ipv6_duplicate_detected(l); - return -1; - } else if (2 == status) { // Router's NCE is full, remove router from default router list - pico_ipv6_route_del(zero, zero, hdr->src, 10, l); - pico_6lp_nd_start_soliciting(pico_ipv6_linklocal_get(l->dev), NULL); - } else { // Registration success - nd_dbg("[6LP-ND]: Registering routable address succeeded!\n"); - } - } - return 0; -} - -/* Add a new 6LoWPAN neighbor with lifetime from ARO */ -static struct pico_ipv6_neighbor *pico_nd_add_6lp(struct pico_ip6 naddr, struct pico_icmp6_opt_aro *aro, struct pico_device *dev) -{ - struct pico_ipv6_neighbor *new = NULL; - - if ((new = pico_nd_add(&naddr, dev))) { - new->expire = PICO_TIME_MS() + (pico_time)(ONE_MINUTE * aro->lifetime); - dbg("ARO Lifetime: %d minutes\n", aro->lifetime); - } else { - return NULL; - } - - return new; -} - -/* RFC6775 §6.5.2. Returning Address Registration Errors */ -static int neigh_sol_dad_reply(struct pico_frame *sol, struct pico_icmp6_opt_lladdr *sllao, struct pico_icmp6_opt_aro *aro, uint8_t status) -{ - uint8_t sllao_len = (uint8_t)(sllao->len * 8); - struct pico_icmp6_hdr *icmp = NULL; - struct pico_frame *adv = pico_frame_copy(sol); - struct pico_ip6 ll = {{0xfe,0x80,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}}; - size_t len = pico_hw_addr_len(sol->dev, sllao); - union pico_ll_addr lladdr; - - if (!adv) { - return -1; - } else { - icmp = (struct pico_icmp6_hdr *)adv->transport_hdr; - - /* Set the status of the Address Registration */ - aro->status = status; - if (PICO_DEV_IS_6LOWPAN(sol->dev)) { - memcpy(lladdr.pan.addr.data, aro->eui64.addr, len); - lladdr.pan.mode = (len == SIZE_6LOWPAN_EXT) ? AM_6LOWPAN_EXT : AM_6LOWPAN_SHORT; - if (pico_6lowpan_lls[sol->dev->mode].addr_iid) - pico_6lowpan_lls[sol->dev->mode].addr_iid(ll.addr + 8, &lladdr); - } - - /* Remove the SLLAO from the frame */ - memmove(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s), ((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s) + sllao_len, (size_t)(aro->len * 8)); - adv->transport_len = (uint16_t)(adv->transport_len - sllao_len); - adv->len = (uint16_t)(adv->len - sllao_len); - - /* I'm a router, and it's always solicited */ - icmp->msg.info.neigh_adv.rsor = 0xE0; - - /* Set the ICMPv6 message type to Neighbor Advertisements */ - icmp->type = PICO_ICMP6_NEIGH_ADV; - icmp->code = 0; - icmp->crc = pico_icmp6_checksum(adv); - - pico_ipv6_frame_push(adv, NULL, &ll, PICO_PROTO_ICMP6, 0); - return 0; - } -} - -/* RFC6775 §6.5.1. Checking for Duplicates */ -static int neigh_sol_detect_dad_6lp(struct pico_frame *f) -{ - struct pico_ipv6_neighbor *n = NULL; - struct pico_icmp6_opt_lladdr *sllao = NULL; - struct pico_icmp6_hdr *icmp = NULL; - struct pico_icmp6_opt_aro *aro = NULL; - size_t len = 0; - - icmp = (struct pico_icmp6_hdr *)f->transport_hdr; - sllao = (struct pico_icmp6_opt_lladdr *)((uint8_t *)&icmp->msg.info.neigh_sol + sizeof(struct neigh_sol_s)); - aro = (struct pico_icmp6_opt_aro *)(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s) + (sllao->len * 8)); - - /* Validate Address Registration Option */ - if (pico_6lp_nd_validate_sol_aro(aro)) - return -1; - - /* See RFC6775 $6.5.1: Checking for duplicates */ - if (!(n = pico_nd_find_neighbor(&icmp->msg.info.neigh_sol.target))) { - /* No dup, add neighbor to cache */ - if (pico_nd_add_6lp(icmp->msg.info.neigh_sol.target, aro, f->dev)) - neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_SUCCES); - else /* No dup, but neighbor cache is full */ - neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_FULL); - return 0; - } else { - if (!aro->lifetime) { - pico_tree_delete(&NCache, n); - PICO_FREE(n); - neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_SUCCES); - return 0; - } - /* Check if hwaddr differs */ - len = pico_hw_addr_len(f->dev, sllao); - if (memcmp(sllao->addr.data, n->hwaddr.data, len) == 0) { - n->expire = PICO_TIME_MS() + (pico_time)(ONE_MINUTE * aro->lifetime); - neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_DUP); - } - return 0; - } -} - -static int router_options(struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt) -{ - /* RFC 4861 $6.1 - * The contents of any defined options that are not specified to be used - * with Router Solicitation messages MUST be ignored and the packet - * processed as normal. The only defined option that may appear is the - * Source Link-Layer Address option. - */ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - uint8_t *options = NULL; - int optlen = 0; - int len = 0; - - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - optlen = f->transport_len - PICO_ICMP6HDR_ROUTER_SOL_SIZE; - if (optlen) - options = ((uint8_t *)&icmp6_hdr->msg.info.router_sol) + sizeof(struct router_sol_s); - - return nd_options(options, opt, expected_opt, optlen, len); -} - -static int router_sol_validity_checks(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - struct pico_icmp6_opt_lladdr opt = { 0 }; - int sllao_present = 0; - - /* Step 2 validation */ - if (f->transport_len < PICO_ICMP6HDR_ROUTER_SOL_SIZE_6LP) - return -1; - - /* RFC4861, 6.1.1: - * - If the IP source address is the unspecified address, there is no - * source link-layer address option in the message. - */ - /* Check for SLLAO if the IP source address is UNSPECIFIED */ - sllao_present = router_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); - if (pico_ipv6_is_unspecified(hdr->src.addr)) { - /* Frame is not valid when SLLAO is present if IP6-SRC is UNSPEC. */ - if (sllao_present) { - return -1; - } - } else { - /* Frame is not valid when no SLLAO if present if there's a IP6-SRC */ - if (sllao_present <= 0) { - return -1; - } - } - - return 0; -} - -static int router_sol_checks(struct pico_frame *f) -{ - /* Step 1 validation */ - if (icmp6_initial_checks(f) < 0) - return -1; - - return router_sol_validity_checks(f); -} - -static int router_sol_process(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = NULL; - - /* Determine if i'm a 6LBR, if i'm not, can't do anything with a router solicitation */ - if (!f->dev->hostvars.routing) - return -1; - - nd_dbg("[6LBR]: Processing router solicitation...\n"); - - /* Router solicitation message validation */ - if (router_sol_checks(f) < 0) - return -1; - - /* Maybe create a tentative NCE? No, will do it later */ - - /* Send a router advertisement via unicast to requesting host */ - hdr = (struct pico_ipv6_hdr *)f->net_hdr; - return pico_icmp6_router_advertisement(f->dev, &hdr->src); -} - -#endif /* PICO_SUPPORT_6LOWPAN */ - -static int pico_nd_router_sol_recv(struct pico_frame *f) -{ -#ifdef PICO_SUPPORT_6LOWPAN - /* 6LoWPAN: reply on explicit router solicitations via unicast */ - if (PICO_DEV_IS_6LOWPAN(f->dev)) - return router_sol_process(f); -#endif - - 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; - uint32_t pref_lifetime = 0; - struct pico_ipv6_hdr *hdr; - struct pico_ip6 zero = { - .addr = {0} - }; - int optlen; -#ifdef PICO_SUPPORT_6LOWPAN - int sllao = 0; -#endif - - 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 - */ - pref_lifetime = long_be(prefix->pref_lifetime); - if (pref_lifetime > long_be(prefix->val_lifetime)) - goto ignore_opt_prefix; - -#ifdef PICO_SUPPORT_6LOWPAN - /* RFC6775 (6LoWPAN): Should the host erroneously receive a PIO with the L (on-link) - * flag set, then that PIO MUST be ignored. - */ - if (PICO_DEV_IS_6LOWPAN(f->dev) && prefix->onlink) - goto ignore_opt_prefix; -#endif - - if (prefix->val_lifetime == 0) - goto ignore_opt_prefix; - - if (prefix->prefix_len != 64) { - return -1; - } - - /* Refresh lifetime of a prefix */ - link = pico_ipv6_prefix_configured(&prefix->prefix); - if (link) { - pico_ipv6_lifetime_set(link, now + (1000 * (pico_time)(long_be(prefix->val_lifetime)))); - goto ignore_opt_prefix; - } - - /* Configure a an non linklocal IPv6 address */ - link = pico_ipv6_link_add_local(f->dev, &prefix->prefix); - if (link) { - pico_ipv6_lifetime_set(link, now + (1000 * (pico_time)(long_be(prefix->val_lifetime)))); - /* Add a default gateway to the default routers list with source of RADV */ - pico_ipv6_route_add(zero, zero, hdr->src, 10, link); -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(f->dev)) { - pico_6lp_nd_register(link); - } -#endif - } - -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; -#ifdef PICO_SUPPORT_6LOWPAN - sllao = 1; // RFC6775 (6LoWPAN): An SLLAO MUST be included in the RA. -#endif - 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; -#ifdef PICO_SUPPORT_6LOWPAN - case PICO_ND_OPT_6CO: - { - struct pico_icmp6_opt_6co *co = (struct pico_icmp6_opt_6co *)nxtopt; -#ifdef PICO_6LOWPAN_IPHC_ENABLED - if (PICO_DEV_IS_6LOWPAN(f->dev)) { - struct pico_ip6 prefix; - memcpy(prefix.addr, (uint8_t *)&co->prefix, (size_t)(co->len - 1) << 3); - ctx_update(prefix, co->id, co->clen, co->lifetime, co->c, f->dev); - } -#endif - optlen -= (co->len << 3); - nxtopt += (co->len << 3); - } - break; - case PICO_ND_OPT_ABRO: - { - struct pico_icmp6_opt_abro *abro = (struct pico_icmp6_opt_abro *)nxtopt; - /* TODO: Process */ - optlen -= (abro->len << 3); - nxtopt += (abro->len << 3); - } - break; -#endif - 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; - } - } -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(f->dev) && !sllao) { - return -1; - } -#endif - 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; - } - - /* ETH: Target address belongs to a tentative link on this device, DaD detected a dup */ - link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target); - if (link && !link->dev->mode) - 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); - } - } - if (!pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL)) { - dbg("IPV6 ND: Failed to start callback timer\n"); - /* TODO no idea what consequences this has */ - } -} - -#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; - /* Do not send periodic router advertisements when there aren't 2 interfaces from and to the device can route */ - if ((!pico_ipv6_is_linklocal(rt->dest.addr)) && dev->hostvars.routing && (rt->link) - && (dev != rt->link->dev) && !PICO_DEV_IS_6LOWPAN(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)); - if (!pico_timer_add(next_timer_expire, pico_ipv6_nd_ra_timer_callback, NULL)) { - dbg("IPv6 ND: Failed to start callback timer\n"); - /* TODO no idea what consequences this has */ - } -} - -/* 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 && !l->dev->mode) - return &l->dev->eth->mac; - else if (l && PICO_DEV_IS_6LOWPAN(l->dev)) - return (struct pico_eth *)l->dev->eth; - - return pico_nd_get(&hdr->dst, f->dev); -} - -void pico_ipv6_nd_postpone(struct pico_frame *f) -{ - int i; - static int last_enq = -1; - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) - { - if (!frames_queued_v6[i]) { - frames_queued_v6[i] = f; - 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] = f; -} - - -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: - nd_dbg("ICMP6: received ROUTER ADV\n"); - 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) -{ - uint32_t timer_cb = 0, ra_timer_cb = 0; - - timer_cb = pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL); - if (!timer_cb) { - nd_dbg("IPv6 ND: Failed to start callback timer\n"); - return; - } - - ra_timer_cb = pico_timer_add(200, pico_ipv6_nd_ra_timer_callback, NULL); - if (!ra_timer_cb) { - nd_dbg("IPv6 ND: Failed to start RA callback timer\n"); - pico_timer_cancel(timer_cb); - return; - } - - if (!pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL)) { - nd_dbg("IPv6 ND: Failed to start check_lifetime timer\n"); - pico_timer_cancel(timer_cb); - pico_timer_cancel(ra_timer_cb); - return; - } -} - -#endif diff --git a/ext/picotcp/modules/pico_ipv6_nd.h b/ext/picotcp/modules/pico_ipv6_nd.h deleted file mode 100644 index 792b229..0000000 --- a/ext/picotcp/modules/pico_ipv6_nd.h +++ /dev/null @@ -1,36 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_ND -#define _INCLUDE_PICO_ND -#include "pico_frame.h" -#include "pico_ipv6.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; -#ifdef PICO_SUPPORT_6LOWPAN - uint8_t lowpan_flags; -#endif -}; - -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); - -#ifdef PICO_SUPPORT_6LOWPAN -int pico_6lp_nd_start_soliciting(struct pico_ipv6_link *l, struct pico_ipv6_route *gw); -void pico_6lp_nd_register(struct pico_ipv6_link *link); -#endif - -#endif diff --git a/ext/picotcp/modules/pico_mcast.c b/ext/picotcp/modules/pico_mcast.c deleted file mode 100644 index 74b4a01..0000000 --- a/ext/picotcp/modules/pico_mcast.c +++ /dev/null @@ -1,259 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - This module handles the equalities between the IGMP and the MLD protocol - 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_igmp.h" -#include "pico_constants.h" -#include "pico_mcast.h" - -#if (((defined(PICO_SUPPORT_MLD) && defined(PICO_SUPPORT_IPV6)) || defined(PICO_SUPPORT_IGMP)) && defined(PICO_SUPPORT_MCAST)) - -#ifdef DEBUG_MCAST -#define multicast_dbg dbg -#else -#define multicast_dbg(...) do {} while(0) -#endif - -#define MCAST_EVENT_DELETE_GROUP (0x0) -#define MCAST_EVENT_CREATE_GROUP (0x1) -#define MCAST_EVENT_UPDATE_GROUP (0x2) -#define MCAST_EVENT_QUERY_RECV (0x3) -#define MCAST_EVENT_REPORT_RECV (0x4) -#define MCAST_EVENT_TIMER_EXPIRED (0x5) - -#define MCAST_MODE_IS_INCLUDE (1) -#define MCAST_MODE_IS_EXCLUDE (2) -#define MCAST_CHANGE_TO_INCLUDE_MODE (3) -#define MCAST_CHANGE_TO_EXCLUDE_MODE (4) - -#define MCAST_MODE_IS_INCLUDE (1) -#define MCAST_MODE_IS_EXCLUDE (2) -#define MCAST_CHANGE_TO_INCLUDE_MODE (3) -#define MCAST_CHANGE_TO_EXCLUDE_MODE (4) -#define MCAST_ALLOW_NEW_SOURCES (5) -#define MCAST_BLOCK_OLD_SOURCES (6) - -typedef int (*mcast_callback)(struct mcast_filter_parameters *); - -static void pico_mcast_src_filtering_cleanup(struct mcast_filter_parameters*mcast ) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - /* cleanup filters */ - pico_tree_foreach_safe(index, mcast->allow, _tmp) - { - pico_tree_delete(mcast->allow, index->keyValue); - } - pico_tree_foreach_safe(index, mcast->block, _tmp) - { - pico_tree_delete(mcast->block, index->keyValue); - } -} -static int pico_mcast_src_filtering_inc_inc(struct mcast_filter_parameters*mcast ) -{ - struct pico_tree_node *index = NULL; - union pico_address *source; - /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */ - if (mcast->p->event == MCAST_EVENT_DELETE_GROUP) { - /* TO_IN (B) */ - mcast->record_type = MCAST_CHANGE_TO_INCLUDE_MODE; - mcast->filter = mcast->allow; - if (mcast->p->MCASTFilter) { - pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ - { - if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - mcast->sources++; - } - } /* else { allow stays empty } */ - - return 0; - } - - /* ALLOW (B-A) */ - /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */ - if (mcast->p->event == MCAST_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */ - mcast->record_type = MCAST_CHANGE_TO_INCLUDE_MODE; - else - mcast->record_type = MCAST_ALLOW_NEW_SOURCES; - - mcast->filter = mcast->allow; - pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ - { - if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - mcast->sources++; - } - pico_tree_foreach(index, &mcast->g->MCASTSources) /* A */ - { - source = pico_tree_findKey(mcast->allow, index->keyValue); - if (source) { - pico_tree_delete(mcast->allow, source); - mcast->sources--; - } - } - if (!pico_tree_empty(mcast->allow)) /* record type is ALLOW */ - return 0; - - /* BLOCK (A-B) */ - mcast->record_type = MCAST_BLOCK_OLD_SOURCES; - mcast->filter = mcast->block; - pico_tree_foreach(index, &mcast->g->MCASTSources) /* A */ - { - if (pico_tree_insert(mcast->block, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - mcast->sources++; - } - pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(mcast->block, index->keyValue); - if (source) { - pico_tree_delete(mcast->block, source); - mcast->sources--; - } - } - if (!pico_tree_empty(mcast->block)) /* record type is BLOCK */ - return 0; - - /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report */ - (mcast->p)->f = NULL; - return MCAST_NO_REPORT; -} - -static int pico_mcast_src_filtering_inc_excl(struct mcast_filter_parameters*mcast ) -{ - struct pico_tree_node *index = NULL; - mcast->record_type = MCAST_CHANGE_TO_EXCLUDE_MODE; - mcast->filter = mcast->block; - pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ - { - if (pico_tree_insert(mcast->block, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - mcast->sources++; - } - return 0; -} -static int pico_mcast_src_filtering_excl_inc(struct mcast_filter_parameters*mcast ) -{ - struct pico_tree_node *index = NULL; - mcast->record_type = MCAST_CHANGE_TO_INCLUDE_MODE; - mcast->filter = mcast->allow; - if (mcast->p->MCASTFilter) { - pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ - { - if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - mcast->sources++; - } - } /* else { allow stays empty } */ - - return 0; -} -static int pico_mcast_src_filtering_excl_excl(struct mcast_filter_parameters*mcast ) -{ - struct pico_tree_node *index = NULL; - struct pico_ip6 *source = NULL; - mcast->record_type = MCAST_BLOCK_OLD_SOURCES; - mcast->filter = mcast->block; - pico_tree_foreach(index, mcast->p->MCASTFilter) - { - if (pico_tree_insert(mcast->block, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - - mcast->sources++; - } - pico_tree_foreach(index, &mcast->g->MCASTSources) /* A */ - { - source = pico_tree_findKey(mcast->block, index->keyValue); /* B */ - if (source) { - pico_tree_delete(mcast->block, source); - mcast->sources--; - } - } - if (!pico_tree_empty(mcast->block)) /* record type is BLOCK */ - return 0; - - /* ALLOW (A-B) */ - mcast->record_type = MCAST_ALLOW_NEW_SOURCES; - mcast->filter = mcast->allow; - pico_tree_foreach(index, &mcast->g->MCASTSources) - { - if (pico_tree_insert(mcast->allow, index->keyValue) == &LEAF) { - multicast_dbg("MCAST: Failed to insert entry in tree\n"); - return -1; - } - mcast->sources++; - } - pico_tree_foreach(index, mcast->p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(mcast->allow, index->keyValue); /* A */ - if (source) { - pico_tree_delete(mcast->allow, source); - mcast->sources--; - } - } - if (!pico_tree_empty(mcast->allow)) /* record type is ALLOW */ - return 0; - - /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report */ - mcast->p->f = NULL; - return MCAST_NO_REPORT; -} -static const mcast_callback mcast_filter_state[2][2] = -{ - { pico_mcast_src_filtering_excl_excl, pico_mcast_src_filtering_excl_inc}, - { pico_mcast_src_filtering_inc_excl, pico_mcast_src_filtering_inc_inc } -}; -int8_t pico_mcast_generate_filter(struct mcast_filter_parameters *filter, struct mcast_parameters *p) -{ - int ret = -1; - /* "non-existent" state of filter mode INCLUDE and empty source list */ - if (p->event == MCAST_EVENT_DELETE_GROUP) { - p->filter_mode = PICO_IP_MULTICAST_INCLUDE; - p->MCASTFilter = NULL; - } - - if (p->event == MCAST_EVENT_QUERY_RECV) - return 0; - - pico_mcast_src_filtering_cleanup(filter); - - if(filter->g->filter_mode <= PICO_IP_MULTICAST_INCLUDE ) - { - if(p->filter_mode <= PICO_IP_MULTICAST_INCLUDE) - { - ret = mcast_filter_state[filter->g->filter_mode][p->filter_mode](filter); - } - } - - return (int8_t) ret; -} -#endif diff --git a/ext/picotcp/modules/pico_mcast.h b/ext/picotcp/modules/pico_mcast.h deleted file mode 100644 index dc9146d..0000000 --- a/ext/picotcp/modules/pico_mcast.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef INCLUDE_PICO_MCAST -#define INCLUDE_PICO_MCAST - -#define MCAST_MODE_IS_INCLUDE (1) -#define MCAST_MODE_IS_EXCLUDE (2) -#define MCAST_CHANGE_TO_INCLUDE_MODE (3) -#define MCAST_CHANGE_TO_EXCLUDE_MODE (4) -#define MCAST_ALLOW_NEW_SOURCES (5) -#define MCAST_BLOCK_OLD_SOURCES (6) -#define MCAST_EVENT_DELETE_GROUP (0x0) -#define MCAST_EVENT_CREATE_GROUP (0x1) -#define MCAST_EVENT_UPDATE_GROUP (0x2) -#define MCAST_EVENT_QUERY_RECV (0x3) -#define MCAST_EVENT_REPORT_RECV (0x4) -#define MCAST_EVENT_TIMER_EXPIRED (0x5) -#define MCAST_NO_REPORT (1) - -PACKED_STRUCT_DEF mcast_parameters { - uint8_t event; - uint8_t state; - uint8_t general_query; - uint8_t filter_mode; - uint8_t last_host; - uint16_t max_resp_time; - union pico_address mcast_link; - union pico_address mcast_group; - struct pico_tree *MCASTFilter; - struct pico_frame *f; -}; - -PACKED_STRUCT_DEF pico_mcast_group { - uint8_t filter_mode; - uint16_t reference_count; - union pico_address mcast_addr; - struct pico_tree MCASTSources; -}; - -PACKED_STRUCT_DEF mcast_filter_parameters { - struct mcast_parameters *p; - struct pico_tree *allow; - struct pico_tree *block; - struct pico_tree *filter; - uint16_t sources; - uint8_t proto; - uint8_t record_type; - struct pico_mcast_group *g; - union pico_link *link; -}; - - -extern int8_t pico_mcast_generate_filter(struct mcast_filter_parameters *filter, struct mcast_parameters *p); - -#endif diff --git a/ext/picotcp/modules/pico_mdns.c b/ext/picotcp/modules/pico_mdns.c deleted file mode 100644 index 2d6cf07..0000000 --- a/ext/picotcp/modules/pico_mdns.c +++ /dev/null @@ -1,3687 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 --- */ -#ifdef DEBUG_MDNS -#define mdns_dbg dbg -#else -#define mdns_dbg(...) do {} while(0) -#endif - -#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) - -#define PICO_MDNS_CTREE_DESTROY(rtree) \ - pico_tree_destroy((rtree), pico_mdns_cookie_delete); - -/* --- 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. - * Following RFC6267: 15.4 Recommendation - * *****************************************************************************/ -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; -} - -/* - * Hash to identify mDNS timers with - */ -static uint32_t mdns_hash = 0; - -/* - * mDNS specific timer creation, to identify if timers are - * created by mDNS module - */ -static uint32_t -pico_mdns_timer_add(pico_time expire, - void (*timer)(pico_time, void *), - void *arg) -{ - return pico_timer_add_hashed(expire, timer, arg, mdns_hash); -} - -#if PICO_MDNS_ALLOW_CACHING == 1 -/* Cache records from mDNS peers on the network */ -static PICO_TREE_DECLARE(Cache, &pico_mdns_record_cmp); -#endif - -/* My records for which I want to have the authority */ -static PICO_TREE_DECLARE(MyRecords, &pico_mdns_record_cmp_name_type); - -/* Cookie-tree */ -static 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) - if (pico_tree_insert(&hits, record) != NULL) - /* either key was already in there, or couldn't be inserted. */ - /* Only delete record if it was copied */ - if (copy) - pico_mdns_record_delete((void **)&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){ - if (pico_tree_insert(&hits, record) != NULL) { - /* either key was already in there, or couldn't be inserted. */ - /* Only delete record if it was copied */ - if (copy) - pico_mdns_record_delete((void **)&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 (!new_rname || 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 */ - if (pico_tree_insert(&new_records, new_record)) { - mdns_dbg("Could not add new non-conflicting record to the tree!\n"); - pico_mdns_record_delete((void **)&new_record); - return new_records; - } - - /* 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){ - if (pico_tree_insert(&new_records, copy)) { - mdns_dbg("MDNS: Failed to insert copy in tree\n"); - pico_mdns_record_delete((void **)©); - return -1; - } - } - - /* 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 RFC6762 - 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), PICO_DNS_CASE_SENSITIVE); -} - -/* **************************************************************************** - * 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; -} - -/* **************************************************************************** - * 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; - uint16_t cl = 0; - - /* Check params */ - if (!url || !_rdata) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } /* Block 1, 2 paths */ - - /* Provide space for the new mDNS resource record */ - if (!(record = PICO_ZALLOC(sizeof(struct pico_mdns_record)))) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } /* Block 2, 1 path */ - else { - /* 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; - } /* Block 3, 2 paths */ - } /* Block 4, Block 3 = 2 paths */ - /* Block 5, (Block 4 + Block 2) * Block 1 = 6 paths */ - - /* Initialise fields */ - record->current_ttl = rttl; - - /* Set the MSB of the DNS class if it's a unique record */ - if (!((flags) & PICO_MDNS_RECORD_SHARED)) { - cl = record->record->rsuffix->rclass; - record->record->rsuffix->rclass = PICO_MDNS_SET_MSB_BE(cl); - } /* Block 6, 2 paths */ - /* Block 7, Block 6 * Block 5 * Block 1 = 12 paths */ - - 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( void **ptr ) -{ - struct pico_mdns_cookie **c = (struct pico_mdns_cookie **)ptr; - - /* 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. - * See RFC6762: 8.2. Simultaneous Probe Tiebreaking - * - * @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, -1 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_mdns_timer_add(1000, pico_mdns_send_probe_packet, - cookie); - if (!cookie->send_timer) { - mdns_dbg("cookie_apply_spt: failed to start timer\n"); - return -1; - } - mdns_dbg("Probing postponed by one second because of S.P.T.\n"); - } - - return 0; -} - -static int -pico_mdns_cookie_del_questions( struct pico_mdns_cookie *cookie, - char *rname ) -{ - uint16_t qc = 0; - - /* Step 1: Remove question with that name from cookie */ - pico_dns_qtree_del_name(&(cookie->qtree), rname); - 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((void **)&cookie); - } - - 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; - 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); - - /* Store some information about a cookie for later on */ - antree = cookie->antree; - callback = cookie->callback; - arg = cookie->arg; - - /* Find the first question in the cookie with the name for which - * the conflict occured. When found, generate a new name. - * - * 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: Check if the new name succeeded, if not: error. */ - if (!new_name) { - /* Delete questions from cookie even if generating a new name failed */ - pico_mdns_cookie_del_questions(cookie, rname); - return -1; - } - - break; - } - } - - /* Step 2: Remove questions with this name from the cookie */ - pico_mdns_cookie_del_questions(cookie, rname); - - /* 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; - } - - if (pico_tree_insert(&MyRecords, record) == &LEAF) { - mdns_dbg("MDNS: Failed to insert record in tree\n"); - return -1; - } - } - } - return 0; -} - -/* **************************************************************************** - * Generates a tree of all My Records for which the probe flag has already - * been set, and for which the CLAIMED flag has NOT 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; - - /* IS_RECORD_VERIFIED() checks the PICO_MDNS_RECORD_PROBED flag */ - 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 PROBED-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(to_probe); - 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(&to_probe, copy)) - pico_mdns_record_delete((void **)©); - } - } - return to_probe; -} - -/* **************************************************************************** - * 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)) { - if (pico_tree_insert(reg_records, record) == &LEAF) { - mdns_dbg("MDNS: Failed to insert record in tree\n"); - return 0; - } - } 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 from 'being probed' to - * 'has been 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_CLR_FLAG(found->flags, PICO_MDNS_RECORD_CURRENTLY_PROBING); - PICO_MDNS_SET_FLAG(found->flags, PICO_MDNS_RECORD_PROBED); - } 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; - } -} - -static int -pico_mdns_cache_flush_name( char *name, struct pico_dns_record_suffix *suffix ) -{ - /* 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, short_be(suffix->rtype))) { - mdns_dbg("Could not flush records from cache!\n"); - return -1; - } - } - - return 0; -} - -/* **************************************************************************** - * 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; - uint32_t rttl = 0; - - /* Check params */ - if (!record) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - /* 2 paths */ - - suffix = record->record->rsuffix; - name = record->record->rname; - rttl = long_be(suffix->rttl); - - if (pico_mdns_cache_flush_name(name, suffix)) { - return -1; - } - /* 4 paths */ - - /* Check if the TTL is not 0*/ - if (!rttl) { - return -1; - } else { - /* 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; - } - /* 12 paths */ -} - -/* **************************************************************************** - * 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((void **)&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 */ - if (!pico_mdns_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_tick, NULL)) { - mdns_dbg("MDNS: Failed to start tick timer\n"); - /* TODO Not ticking anymore, what to do? */ - } -} - -/* 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 sent on the wire. - * ****************************************************************************/ -static int -pico_mdns_send_packet( pico_dns_packet *packet, uint16_t len ) -{ - /* TODO: why only ipv4 support? */ - 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 */ - - /* RFC6762: 18.6: In both multicast query and response messages, - the RD bit SHOULD be zero on transmission. In - pico_dns_fill_packet_header, the RD bit is set to - PICO_DNS_RD_IS_DESIRED, which is defined to be 1 */ - packet->rd = PICO_DNS_RD_NO_DESIRE; - - - 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; - - /* RFC6762: 18.6: In both multicast query and response messages, - the RD bit SHOULD be zero on transmission. - In pico_dns_fill_packet_header, the RD bit is set to - PICO_DNS_RD_IS_DESIRED, which is defined to be 1 */ - packet->rd = PICO_DNS_RD_NO_DESIRE; - - /* 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) { - if (pico_tree_insert(dest, node->keyValue) == &LEAF) { - mdns_dbg("MDNS: Failed to insert record in tree\n"); - return -1; - } - } - } - - 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. */ - if (pico_tree_insert(&antree, answer) == &LEAF) { - mdns_dbg("MDNS: Failed to insert answer in tree\n"); - return -1; - } - 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; - } - - /* TODO: When receiving multiple authoritative answers, */ - /* they should be sorted in lexicographical order */ - /* (just like in pico_mdns_record_am_i_lexi_later) */ - - 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){ - if (pico_tree_insert(unicast_tree, record->record) == &LEAF) { - mdns_dbg("MDNS: Failed to instert unicast record in tree\n"); - return -1; - } - } - } else { - if (record->record){ - if (pico_tree_insert(multicast_tree, record->record) == &LEAF) { - mdns_dbg("MDNS: Failed to instert multicast record in tree\n"); - return -1; - } - } - } - } - } - - 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) && 0 == strcasecmp(record->record->rname, name)) { - return 0; - } - } - } - - /* If there is none present generate one for given name */ - if ((nsec = pico_mdns_gen_nsec_record(name))) { - if (pico_tree_insert(artree, nsec)) { - pico_mdns_record_delete((void **)nsec); - return -1; - } - } - - 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) { - record = node->keyValue; - if (record) { - if (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; -} /* Satic path count: 4 */ - -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 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; - - /* Generate proper service instance name and service */ - sin = pico_dns_qname_to_url(srv_record->record->rname); // May be leaking - - if (!antree || !artree || !sin) { - pico_err = PICO_ERR_EINVAL; - PICO_FREE(sin); - return -1; - } else { - /* Add hostname records */ - pico_mdns_additionals_add_host(artree); - - 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); // Free allocated memory - 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, alread in, destroy */ - if (pico_tree_insert(&MyRecords, meta_record)) { - mdns_dbg("MDNS: Failed to insert meta record in tree\n"); - pico_mdns_record_delete((void **)&meta_record); - pico_mdns_record_delete((void **)&ptr_record); - return -1; - } - - if (pico_tree_insert(&MyRecords, ptr_record)) { - mdns_dbg("MDNS: Failed to insert ptr record in tree\n"); - pico_mdns_record_delete((void **)&ptr_record); - pico_tree_delete(&MyRecords, meta_record); - pico_mdns_record_delete((void **)&meta_record); - } - } - return 0; -} /* Static path count: 9 */ - -/* **************************************************************************** - * 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; - } else { - /* Look for SRV records in the 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 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 additionals 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; -} /* Static path count: 9 */ - -/* **************************************************************************** - * 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); - - /* RFC6762: */ - /* 18.3: Messages received with an opcode other than zero MUST be silently */ - /* ignored. */ - /* 18.11: messages received with non-zero Response Codes MUST be silently */ - /* ignored */ - if(packet->opcode == 0 && packet->rcode == 0) { - 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 */ - 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; - - /* RFC6762: 18.6: In both multicast query and response messages, - the RD bit SHOULD be zero on transmission. In pico_dns_fill_packet_header, - the RD bit is set to PICO_DNS_RD_IS_DESIRED, which is defined to be 1 */ - packet->rd = PICO_DNS_RD_NO_DESIRE; - - 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((void **)&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; - } - - if (pico_tree_insert(&qtree, q)) { - mdns_dbg("inserting query into tree failed!\n"); - pico_dns_question_delete((void **)&q); - return -1; - } - - - /* 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 */ - if(pico_tree_insert(&Cookies, cookie) ){ - mdns_dbg("inserting cookie into tree failed!\n"); - PICO_DNS_QTREE_DESTROY(&qtree); - pico_mdns_cookie_delete((void **)&cookie); - return -1; - } - - /* Create new pico_timer-event to send packet */ - if (!pico_mdns_timer_add((pico_rand() % 120) + 20, pico_mdns_send_query_packet, - (void *)cookie)) { - mdns_dbg("MDNS: Failed to start send_query_packet timer\n"); - pico_tree_delete(&Cookies, cookie); - pico_mdns_cookie_delete((void**)&cookie); - pico_dns_question_delete((void**)&q); - return -1; - } - - 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 to 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 -} -return 0; -#endif -} - -/* 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 Multicast DNS responder MUST send at least two unsolicited - responses, one second apart. To provide increased robustness - against packet loss, a responder MAY send up to eight unsolicited - responses, provided that the interval between unsolicited - responses increases by at least a factor of two with - every response sent. - */ - --(cookie->count); - 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((void **)&cookie); - } - else{ - /* - A responder MAY send up to eight unsolicited responses, - provided that the interval between unsolicited responses increases - by at least a factor of two with every response sent. - Starting at 1 second. - So we bithsift to get our powers of two and we multiply by 1000 to - get our miliseconds. - */ - if (!pico_mdns_timer_add((pico_time)((1 << (PICO_MDNS_ANNOUNCEMENT_COUNT - cookie->count - 1)) - * 1000), pico_mdns_send_announcement_packet, cookie)) { - mdns_dbg("MDNS: Failed to start send_announcement_packet timer\n"); - /* TODO no idea what the consequences of this are */ - - } - } - } -} - -/* **************************************************************************** - * 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 */ - if (pico_tree_insert(&nstree, record->record) == &LEAF) { - mdns_dbg("MDNS: Failed to insert record in tree\n"); - break; - } - } - } - - return nstree; -} - -/* **************************************************************************** - * Function to create a probe from 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)) { */ - if (!cookie || (cookie->type != PICO_MDNS_PACKET_TYPE_PROBE)) { - pico_err = PICO_ERR_EINVAL; - return; - } else { - /* Set the cookie to the active state */ - cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; - if (cookie->count > 0) { - --(cookie->count); - - /* 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); - - /* RFC6762: 18.1 */ - packet->id = 0; - - /* RFC6762: 18.6: In both multicast query and response messages, - the RD bit SHOULD be zero on transmission. - In pico_dns_fill_packet_header, the RD bit is set to - PICO_DNS_RD_IS_DESIRED, which is defined to be 1 */ - packet->rd = PICO_DNS_RD_NO_DESIRE; - - /* 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_mdns_timer_add(250, - pico_mdns_send_probe_packet, - (void *)cookie); - if (!cookie->send_timer) { - mdns_dbg("MDNS: Failed to start send_probe_packet timer\n"); - /* TODO no idea what the consequences of this are */ - return; - } - } - } 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); - } - } -} /* Static path count: 10 */ - -/* **************************************************************************** - * 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; - } else { - /* Find my records that need to pass the probing step first - * All records that don't have their PROBED flag set and - * are not being probed at hte moment are added to the tree - */ - antree = pico_mdns_my_records_find_to_probe(); - - /* Create probe questions for the records to be probed */ - 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((void **)&cookie); - return -1; - } - - /* RFC6762: 8.1. Probing */ - /* When ready to send its Multicast DNS probe packet(s) the host should */ - /* first wait for a short random delay time, uniformly distributed in */ - /* the range 0-250 ms. */ - cookie->send_timer = pico_mdns_timer_add(pico_rand() % 250, - pico_mdns_send_probe_packet, - (void *)cookie); - if (!cookie->send_timer) { - mdns_dbg("MDNS: Failed to start send_probe_packet timer\n"); - pico_tree_delete(&Cookies, cookie); - pico_mdns_cookie_delete((void**)&cookie); - return -1; - } - - mdns_dbg("DONE - Started probing.\n"); - } - return 0; -} /* Static path count: 9 */ - -/* 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, PICO_MDNS_NO_RECLAIM, 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, PICO_MDNS_RECLAIM, callback, arg); -} - -/* **************************************************************************** - * Tries to claim a 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 succeeded. - * 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_tryclaim_hostname( const char *url, void *arg ) -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *record = NULL; - - /* 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; - } else { - /* 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; -} /* Static path count: 9 */ - -/* **************************************************************************** - * 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; -} - -static void -pico_mdns_cleanup( void ) -{ - /* Delete socket if it was previously opened */ - if (mdns_sock_ipv4) { - pico_socket_del(mdns_sock_ipv4); - } - - /* Clear out every memory structure used by mDNS */ -#if PICO_MDNS_ALLOW_CACHING == 1 - PICO_MDNS_RTREE_DESTROY(&Cache); -#endif /* PICO_MDNS_ALLOW_CACHING */ - PICO_MDNS_RTREE_DESTROY(&MyRecords); - PICO_MDNS_CTREE_DESTROY(&Cookies); - - /* Cancel every timer */ - pico_timer_cancel_hashed(mdns_hash); -} - -/* **************************************************************************** - * 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; - } - - /* Clear out all the memory structure's and delete socket if it was - * already opened before */ - pico_mdns_cleanup(); - - /* Create a hash to identify mDNS timers with */ - mdns_hash = pico_hash(hostname, (uint32_t)strlen(hostname)); - - /* 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; - } - - /* RFC6762: - * 11. Source Address Check - * All Multicast DNS responses (including responses sent via unicast) - * SHOULD be sent with IP TTL set to 255. - */ - 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; - if (!pico_mdns_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_tick, NULL)) { - mdns_dbg("MDNS: Failed to start tick timer\n"); - return -1; - } - - /* Set the hostname eventually */ - return pico_mdns_tryclaim_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 54c8ede..0000000 --- a/ext/picotcp/modules/pico_mdns.h +++ /dev/null @@ -1,206 +0,0 @@ -/* **************************************************************************** - * PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. - * See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 3 -/* Amount of probes to send: - RFC6762: 8.1. Probing: - 250 ms after the first query, the host should send a second; then, - 250 ms after that, a third. If, by 250 ms after the third probe, no - conflicting Multicast DNS responses have been received, the host may - move to the next step, announcing. - */ - -#define PICO_MDNS_ANNOUNCEMENT_COUNT 3 -/* Amount of announcements to send: (we've opted for 1 extra for robustness) - RFC6762: 8.3. Announcing: - The Multicast DNS responder MUST send at least two unsolicited - responses, one second apart. To provide increased robustness against - packet loss, a responder MAY send up to eight unsolicited responses, - provided that the interval between unsolicited responses increases by - at least a factor of two with every response sent. - */ -/* ****************************************************************************/ - -#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 - -/* To indicate if we reclaim or not */ -#define PICO_MDNS_RECLAIM 1 -#define PICO_MDNS_NO_RECLAIM 0 - -/* 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 ); - -/* **************************************************************************** - * Tries to claim a 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 succeeded. - * 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_tryclaim_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 c362acf..0000000 --- a/ext/picotcp/modules/pico_mld.c +++ /dev/null @@ -1,1165 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" -#include "pico_mcast.h" - -#if defined(PICO_SUPPORT_MLD) && defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_MCAST) - -#ifdef DEBUG_MLD -#define mld_dbg dbg -#else -#define mld_dbg(...) do {} while(0) -#endif - -/* 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) - -static 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[1]; -}; -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[1]; -}; -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[1]; -}; -typedef int (*mld_callback)(struct mcast_parameters *); -static int pico_mld_process_event(struct mcast_parameters *p); -static struct mcast_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; i < MLD_ROUTER_ALERT_LEN - 2; i++) { - if( *(p + i) != options[i + 2]) - return -1; - } - return 0; -} -static inline int mldt_type_compare(struct mld_timer *a, struct mld_timer *b) -{ - if (a->type < 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 mcast_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); -} -static 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 mcast_parameters *a, struct mcast_parameters *b) -{ - return pico_ipv6_compare(&a->mcast_group.ip6, &b->mcast_group.ip6); -} -static inline int mldparm_link_compare(struct mcast_parameters *a, struct mcast_parameters *b) -{ - return pico_ipv6_compare(&a->mcast_link.ip6, &b->mcast_link.ip6); -} -static int mcast_parameters_cmp(void *ka, void *kb) -{ - struct mcast_parameters *a = ka, *b = kb; - int cmp = mldparm_group_compare(a, b); - if (cmp) - return cmp; - - return mldparm_link_compare(a, b); -} - -static PICO_TREE_DECLARE(MLDParameters, mcast_parameters_cmp); - -static int pico_mld_delete_parameter(struct mcast_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 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 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 %lu\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 DEBUG_MLD - mld_dbg("MLD: restart timer for %s, delay %lu, new delay %lu\n", grpstr, t->delay, (timer->start + timer->delay) - PICO_TIME_MS()); -#endif - if (!pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_mld_timer_expired, timer)) { - mld_dbg("MLD: Failed to start expiration timer\n"); - pico_tree_delete(&MLDTimers, timer); - PICO_FREE(timer); - } - } - - return; -} - -static int pico_mld_timer_reset(struct mld_timer *t) -{ - struct mld_timer *timer = NULL, test = { - 0 - }; -#ifdef 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 %lu\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 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 %lu\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(); - if (pico_tree_insert(&MLDTimers, timer)) { - mld_dbg("MLD: Failed to insert timer into tree\n"); - return -1; - } - - if (!pico_timer_add(timer->delay, &pico_mld_timer_expired, timer)) { - mld_dbg("MLD: Failed to start expiration timer\n"); - pico_tree_delete(&MLDTimers, timer); - PICO_FREE(timer); - return -1; - } - return 0; -} - -static int pico_mld_timer_stop(struct mld_timer *t) -{ - struct mld_timer *timer = NULL, test = { - 0 - }; -#ifdef 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 DEBUG_MLD - pico_ipv6_to_string(grpstr, timer->mcast_group.addr); - mld_dbg("MLD: stop timer for %s, delay %lu\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); -} - -static PICO_TREE_DECLARE(MLDAllow, mld_sources_cmp); -static PICO_TREE_DECLARE(MLDBlock, mld_sources_cmp); - -static struct mcast_parameters *pico_mld_find_parameter(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group) -{ - struct mcast_parameters test = { - 0 - }; - if (!mcast_link || !mcast_group) - return NULL; - - test.mcast_link.ip6 = *mcast_link; - test.mcast_group.ip6 = *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; - struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *) (f->transport_hdr + MLD_ROUTER_ALERT_LEN); - struct mcast_parameters *p = NULL; - struct pico_ip6 mcast_group = {{ - 0 - }}; - struct mld_message *mld_report = (struct mld_message *) hdr; - - 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; - - /* Reset states to prevent deadlock */ - mcast_group = mld_report->mcast_group; - p = pico_mld_find_parameter(&link->address, &mcast_group); - if(p) { - p->state = MLD_STATE_NON_LISTENER; - p->event = MLD_EVENT_START_LISTENING; - } - - 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; - if (pico_mld_timer_start(&t) < 0) - return -1; - } 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 mcast_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 mcast_parameters)); - if (!p) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (!mcast_link || !mcast_group) { - pico_err = PICO_ERR_EINVAL; - PICO_FREE(p); - return -1; - } - - p->state = MLD_STATE_NON_LISTENER; - p->mcast_link.ip6 = *mcast_link; - p->mcast_group.ip6 = *mcast_group; - if(pico_tree_insert(&MLDParameters, p)){ - PICO_FREE(p); - return -1; - } - } 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 mcast_parameters *p); - -static struct mcast_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 mcast_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 mcast_parameters)); - if(!p) - return NULL; - - p->state = MLD_STATE_NON_LISTENER; - p->mcast_link.ip6 = link->address; - if (pico_tree_insert(&MLDParameters, p)) { - PICO_FREE(p); - return NULL; - } - } - - 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 mcast_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 mcast_parameters *p, struct pico_frame *f) -{ - struct mld_message *report = NULL; - uint8_t report_type = PICO_MLD_DONE; - struct pico_device *dev = NULL; - struct pico_ipv6_exthdr *hbh; - struct pico_ip6 dst = {{ 0 }}; -#ifdef 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]); - dev = pico_ipv6_link_find(&p->mcast_link.ip6); - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, sizeof(struct mld_message) + MLD_ROUTER_ALERT_LEN); - /* 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.ip6; - - report->crc = 0; - /* Checksum done in ipv6 module, no need to do it twice */ - /* report->crc = short_be(pico_icmp6_checksum(p->f)); */ -#ifdef DEBUG_MLD - pico_ipv6_to_string(ipstr, dst.addr); - pico_ipv6_to_string(grpstr, report->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 mcast_parameters *p, struct pico_frame *f) -{ - struct pico_ip6 dst = {{ - 0 - }}; - struct pico_ip6 mcast_group = {{ - 0 - }}; -#ifdef 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.ip6); - if (!link) - return -1; - - mcast_group = p->mcast_group.ip6; - 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 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_mldv2_generate_report(struct mcast_filter_parameters *filter, struct mcast_parameters *p) -{ - struct mldv2_report *report = NULL; - struct mldv2_group_record *record = NULL; - struct pico_tree_node *index = NULL; - struct pico_ipv6_hbhoption *hbh; - struct pico_device *dev = NULL; - uint16_t len = 0; - uint16_t i = 0; - /* RFC3810 $5.1.10 */ - if(filter->sources > MLD_MAX_SOURCES) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - len = (uint16_t)(sizeof(struct mldv2_report) + sizeof(struct mldv2_group_record) \ - + (filter->sources * sizeof(struct pico_ip6)) + MLD_ROUTER_ALERT_LEN); - len = (uint16_t)(len - sizeof(struct pico_ip6)); - dev = pico_ipv6_link_find(&p->mcast_link.ip6); - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, len); - /* 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 = filter->record_type; - record->aux = 0; - record->nbr_src = short_be(filter->sources); - record->mcast_group = p->mcast_group.ip6; - if (filter->filter && !pico_tree_empty(filter->filter)) { - i = 0; - pico_tree_foreach(index, filter->filter) - { - record->src[i] = (*(struct pico_ip6 *)index->keyValue); - i++; - } - } - - if(i != filter->sources) { - return -1; - } - - /* Checksum done in ipv6 module, no need to do it twice */ - /* report->crc= short_be(pico_mld_checksum(p->f)); */ - return 0; -} -static int8_t pico_mldv2_generate_filter(struct mcast_filter_parameters *filter, struct mcast_parameters *p) -{ - struct pico_mcast_group *g = NULL, test = { - 0 - }; - struct pico_tree *MLDFilter = NULL; - struct pico_ipv6_link *link = (struct pico_ipv6_link*) filter->link; - filter->p = (struct mcast_parameters *)p; - filter->allow = &MLDAllow; - filter->block = &MLDBlock; - filter->filter = MLDFilter; - filter->sources = 0; - filter->proto = PICO_MLDV2; - test.mcast_addr = p->mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - filter->g = (struct pico_mcast_group *)g; - return pico_mcast_generate_filter(filter, p); - -} -static int8_t pico_mldv1_generate_report(struct mcast_parameters *p) -{ - struct mld_message *report = NULL; - uint8_t report_type = PICO_MLD_REPORT; - struct pico_ipv6_exthdr *hbh; - struct pico_device *dev = pico_ipv6_link_find(&p->mcast_link.ip6); - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, sizeof(struct mld_message) + MLD_ROUTER_ALERT_LEN ); - /* 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.ip6; - - report->crc = 0; - /* Checksum done in ipv6 module, no need to do it twice */ - /* report->crc = short_be(pico_icmp6_checksum(p->f)); */ - return 0; -} -static int8_t pico_mld_generate_report(struct mcast_parameters *p) -{ - struct mcast_filter_parameters filter; - int8_t result; - filter.link = (union pico_link *)pico_ipv6_link_get(&p->mcast_link.ip6); - if( !filter.link || !pico_ipv6_is_multicast(p->mcast_group.ip6.addr)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (filter.link->ipv6.mcast_compatibility) { - - case PICO_MLDV1: { - return pico_mldv1_generate_report(p); - } - case PICO_MLDV2: { - result = pico_mldv2_generate_filter(&filter, p); - if(result < 0) - return -1; - - if(result != MCAST_NO_REPORT) - return pico_mldv2_generate_report(&filter, p); - } - break; - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} -/* stop timer, send done if flag set */ -static int mld_stsdifs(struct mcast_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.ip6); - 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.ip6; - t.mcast_group = p->mcast_group.ip6; - 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 mcast_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.ip6; - t.mcast_group = p->mcast_group.ip6; - - t.delay = (pico_rand() % (MLD_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.mld_callback = pico_mld_report_expired; - - if (pico_mld_timer_start(&t) < 0) - return -1; - - 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 mcast_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.ip6; - t.mcast_group = p->mcast_group.ip6; - 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 mcast_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 mcast_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.ip6, &p->mcast_group.ip6); - 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 mcast_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.ip6); - 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.ip6, &p->mcast_group.ip6); - 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 mcast_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.ip6); - 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.ip6; - t.mcast_group = p->mcast_group.ip6; - t.delay = (pico_rand() % (MLD_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.mld_callback = pico_mld_report_expired; - - if (pico_mld_timer_start(&t) < 0) - return -1; - - p->state = MLD_STATE_DELAYING_LISTENER; - mld_dbg("MLD: new state = delaying member\n"); - return 0; -} -static int mld_discard(struct mcast_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 mcast_parameters *p) -{ - struct pico_tree_node *index = NULL; - struct mcast_parameters *_p; -#ifdef DEBUG_MLD - char ipv6[PICO_IPV6_STRING]; - pico_ipv6_to_string(ipv6, p->mcast_group.ip6.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 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 4318162..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 COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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[1]; -}; - -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 f2553c1..0000000 --- a/ext/picotcp/modules/pico_mm.c +++ /dev/null @@ -1,1615 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 */ - -#ifdef DEBUG_MM -#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 ) -#else -#define DBG_MM(x, args ...) do {} while(0) -#define DBG_MM_RED(x, args ...) do {} while(0) -#define DBG_MM_GREEN(x, args ...) do {} while(0) -#define DBG_MM_YELLOW(x, args ...) do {} while(0) -#define DBG_MM_BLUE(x, args ...) do {} while(0) -#endif - -/* 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; -#ifdef DEBUG_MM - uint16_t i = 0; -#endif - - 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; -#ifdef DEBUG_MM - uint16_t i = 0; -#endif - - /* 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 93bd102..0000000 --- a/ext/picotcp/modules/pico_mm.h +++ /dev/null @@ -1,98 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 b8f08e0..0000000 --- a/ext/picotcp/modules/pico_nat.c +++ /dev/null @@ -1,589 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -#ifdef DEBUG_NAT -#define nat_dbg dbg -#else -#define nat_dbg(...) do {} while(0) -#endif - -#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); -} - -static PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound); -static 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++; - break; - - 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(); - if (!pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL)) { - nat_dbg("NAT: Failed to start cleanup timer\n"); - /* TODO no more NAT table cleanup now */ - } -} - -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; - } - - if (!pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL)) { - nat_dbg("NAT: Failed to start cleanup timer\n"); - return -1; - } - - nat_link = link; - - 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 b6d7010..0000000 --- a/ext/picotcp/modules/pico_nat.h +++ /dev/null @@ -1,90 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 b606e5b..0000000 --- a/ext/picotcp/modules/pico_olsr.c +++ /dev/null @@ -1,1167 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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) - -#ifdef DEBUG_OLSR -#define olsr_dbg dbg -#else -#define olsr_dbg(...) do {} while(0) -#endif - -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; - if (!pico_timer_add(1 + when - ((pico_rand() % OLSR_MAXJITTER)), &olsr_process_out, p)) { - olsr_dbg("OLSR: Failed to start process timer\n"); - OOM(); - PICO_FREE(p); - PICO_FREE(buffer); - } -} - - -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; - } - if (!pico_timer_add(OLSR_HELLO_INTERVAL, &olsr_hello_tick, NULL)) { - olsr_dbg("OLSR: Failed to start hello_tick timer\n"); - /* TODO no more ticks now */ - } -} - -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; - } - if (!pico_timer_add(OLSR_TC_INTERVAL, &olsr_tc_tick, NULL)) { - olsr_dbg("OLSR: Failed to start tc_tick timer\n"); - /* TODO no more ticks now */ - } -} - - -/* Public interface */ - -void pico_olsr_init(void) -{ - uint32_t hello_timer = 0; - 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); - } - - hello_timer = pico_timer_add(pico_rand() % 100, &olsr_hello_tick, NULL); - if (!hello_timer) { - olsr_dbg("OLSR: Failed to start hello_tick timer\n"); - return; - } - if (!pico_timer_add(pico_rand() % 900, &olsr_tc_tick, NULL)) { - olsr_dbg("OLSR: Failed to start tc_tick timer\n"); - pico_timer_cancel(hello_timer); - } -} - - -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 b111188..0000000 --- a/ext/picotcp/modules/pico_olsr.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 659cb4c..0000000 --- a/ext/picotcp/modules/pico_posix.c +++ /dev/null @@ -1,99 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 7b11cf8..0000000 --- a/ext/picotcp/modules/pico_slaacv4.c +++ /dev/null @@ -1,307 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -#ifdef DEBUG_SLAACV4 -#define slaacv4_dbg dbg -#else -#define slaacv4_dbg(...) do {} while(0) -#endif - -#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); - if (!tmp->timer) { - slaacv4_dbg("SLAACV4: Failed to start announce timer\n"); - tmp->state = SLAACV4_ERROR; - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - } - 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); - if (!tmp->timer) { - slaacv4_dbg("SLAACV4: Failed to start probe timer\n"); - tmp->state = SLAACV4_ERROR; - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - } - else - { - tmp->state = SLAACV4_ANNOUNCING; - tmp->timer = pico_timer_add(ANNOUNCE_WAIT * 1000, pico_slaacv4_send_announce_timer, arg); - if (!tmp->timer) { - slaacv4_dbg("SLAACV4: Failed to start announce timer\n"); - tmp->state = SLAACV4_ERROR; - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - } -} - -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); - if (!tmp->timer) { - slaacv4_dbg("SLAACV4: Failed to start probe timer\n"); - tmp->state = SLAACV4_ERROR; - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - } - 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); - if (!tmp->timer) { - slaacv4_dbg("SLAACV4: Failed to start probe timer\n"); - tmp->state = SLAACV4_ERROR; - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - } - 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); - if (!tmp->timer) { - slaacv4_dbg("SLAACV4: Failed to start probe timer\n"); - tmp->state = SLAACV4_ERROR; - if (tmp->cb != NULL) - tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR); - } - } - 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; - } - } - 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); - if (!slaacv4_local.timer) { - slaacv4_dbg("SLAACV4: Failed to start probe timer\n"); - slaacv4_local.state = SLAACV4_ERROR; - return -1; - } - } - - 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 8912dbd..0000000 --- a/ext/picotcp/modules/pico_slaacv4.h +++ /dev/null @@ -1,18 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 3b68bb2..0000000 --- a/ext/picotcp/modules/pico_sntp_client.c +++ /dev/null @@ -1,552 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 - -#ifdef DEBUG_SNTP -#define sntp_dbg dbg -#else -#define sntp_dbg(...) do {} while(0) -#endif - -#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: %lu\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: %lusec, %lumsec\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; - - pico_timer_cancel(ck->timer); - - 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: %lu seconds and %lu 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); - s->priv = NULL; /* make sure UDP callback does not try to read from freed mem again */ - 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); - if (!ck->timer) { - sntp_dbg("SNTP: Failed to start timeout timer\n"); - pico_sntp_cleanup(ck, pico_err); - pico_socket_close(sock); - pico_socket_del(sock); - return; - } - 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)); -} - -static int pico_sntp_sync_start(struct sntp_server_ns_cookie *ck, union pico_address *addr) -{ - uint16_t any_port = 0; - struct pico_socket *sock; - - sock = pico_socket_open(ck->proto, PICO_PROTO_UDP, &pico_sntp_client_wakeup); - if (!sock) - return -1; - - sock->priv = ck; - ck->sock = sock; - if ((pico_socket_bind(sock, &sntp_inaddr_any, &any_port) < 0)) { - pico_socket_close(sock); - return -1; - } - pico_sntp_send(sock, addr); - - return 0; -} - -#ifdef PICO_SUPPORT_DNS_CLIENT -/* 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; - int retval = -1; - - if(!ck) { - sntp_dbg("dnsCallback: Invalid argument\n"); - return; - } - - if(ck->proto == PICO_PROTO_IPV6) { -#ifdef PICO_SUPPORT_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 - } else if(ck->proto == PICO_PROTO_IPV4) { -#ifdef PICO_SUPPORT_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) { - retval = pico_sntp_sync_start(ck, &address); - if (retval < 0) - pico_sntp_cleanup(ck, PICO_ERR_ENOTCONN); - } -} -#endif - -#ifdef PICO_SUPPORT_IPV4 -#ifdef PICO_SUPPORT_DNS_CLIENT -static int pico_sntp_sync_start_dns_ipv4(const char *sntp_server, void (*cb_synced)(pico_err_t status)) -{ - int retval = -1; - struct sntp_server_ns_cookie *ck; - /* 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); - - ck->cb_synced = cb_synced; - - 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; -} -#endif -static int pico_sntp_sync_start_ipv4(union pico_address *addr, void (*cb_synced)(pico_err_t status)) -{ - int retval = -1; - struct sntp_server_ns_cookie *ck; - 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; - /* Set the given IP address as hostname, allocate the maximum IPv4 string length + 1 */ - ck->hostname = PICO_ZALLOC(15 + 1); - if (!ck->hostname) { - PICO_FREE(ck); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - retval = pico_ipv4_to_string(ck->hostname, addr->ip4.addr); - if (retval < 0) { - PICO_FREE(ck->hostname); - PICO_FREE(ck); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - ck->cb_synced = cb_synced; - - retval = pico_sntp_sync_start(ck, addr); - if (retval < 0) { - pico_sntp_cleanup(ck, PICO_ERR_ENOTCONN); - return -1; - } - - return 0; -} -#endif - -#ifdef PICO_SUPPORT_IPV6 -#ifdef PICO_SUPPORT_DNS_CLIENT -static int pico_sntp_sync_start_dns_ipv6(const char *sntp_server, void (*cb_synced)(pico_err_t status)) -{ - struct sntp_server_ns_cookie *ck6; - int retval6 = -1; - /* 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; - } - - return 0; -} -#endif -static int pico_sntp_sync_start_ipv6(union pico_address *addr, void (*cb_synced)(pico_err_t status)) -{ - struct sntp_server_ns_cookie *ck6; - int retval6 = -1; - ck6 = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - if (!ck6) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - ck6->proto = PICO_PROTO_IPV6; - ck6->stamp = 0ull; - ck6->rec = 0; - ck6->sock = NULL; - ck6->cb_synced = cb_synced; - /* Set the given IP address as hostname, allocate the maximum IPv6 string length + 1 */ - ck6->hostname = PICO_ZALLOC(39 + 1); - if (!ck6->hostname) { - PICO_FREE(ck6); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - retval6 = pico_ipv6_to_string(ck6->hostname, addr->ip6.addr); - if (retval6 < 0) { - PICO_FREE(ck6->hostname); - PICO_FREE(ck6); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - retval6 = pico_sntp_sync_start(ck6, addr); - if (retval6 < 0) { - pico_sntp_cleanup(ck6, PICO_ERR_ENOTCONN); - return -1; - } - - return 0; -} -#endif - -/* user function to sync the time from a given sntp source in string notation, DNS resolution is needed */ -int pico_sntp_sync(const char *sntp_server, void (*cb_synced)(pico_err_t status)) -{ -#ifdef PICO_SUPPORT_DNS_CLIENT - int retval4 = -1, retval6 = -1; - if (sntp_server == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if(cb_synced == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - -#ifdef PICO_SUPPORT_IPV4 - retval4 = pico_sntp_sync_start_dns_ipv4(sntp_server, cb_synced); -#endif -#ifdef PICO_SUPPORT_IPV6 - retval6 = pico_sntp_sync_start_dns_ipv6(sntp_server, cb_synced); -#endif - - if (retval4 != 0 && retval6 != 0) - return -1; - - return 0; -#else - sntp_debug("No DNS support available\n"); - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -#endif -} - -/* user function to sync the time from a given sntp source in pico_address notation */ -int pico_sntp_sync_ip(union pico_address *sntp_addr, void (*cb_synced)(pico_err_t status)) -{ - int retval4 = -1, retval6 = -1; - if (sntp_addr == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (cb_synced == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - -#ifdef PICO_SUPPORT_IPV4 - retval4 = pico_sntp_sync_start_ipv4(sntp_addr, cb_synced); -#endif -#ifdef PICO_SUPPORT_IPV6 - retval6 = pico_sntp_sync_start_ipv6(sntp_addr, cb_synced); -#endif - - if (retval4 != 0 && retval6 != 0) - 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: %lu seconds and %lu 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 21ee5ed..0000000 --- a/ext/picotcp/modules/pico_sntp_client.h +++ /dev/null @@ -1,23 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_sync_ip(union pico_address *sntp_addr, 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 569e4e8..0000000 --- a/ext/picotcp/modules/pico_socket_tcp.c +++ /dev/null @@ -1,272 +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_socket *target = 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) - { - target = found; - if ( found->remote_port != 0) - /* only break if it's connected */ - break; - } - } /* FOREACH */ - - return socket_tcp_do_deliver(target, 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 9ec1bfd..0000000 --- a/ext/picotcp/modules/pico_socket_udp.c +++ /dev/null @@ -1,260 +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; -} - - -#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6) -static int pico_enqueue_and_wakeup_if_needed(struct pico_queue *q_in, struct pico_socket* s, struct pico_frame* cpy) -{ - if (pico_enqueue(q_in, cpy) > 0) { - if (s->wakeup){ - s->wakeup(PICO_SOCK_EV_RD, s); - } - } - else { - pico_frame_discard(cpy); - return -1; - } - return 0; -} -#endif - -#ifdef PICO_SUPPORT_IPV4 -#ifdef PICO_SUPPORT_MCAST -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; - - pico_enqueue_and_wakeup_if_needed(&s->q_in, s, cpy); - } - - return 0; -} -#endif -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; - - pico_enqueue_and_wakeup_if_needed(&s->q_in, s, 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)) { -#ifdef PICO_SUPPORT_MCAST - ret = pico_socket_udp_deliver_ipv4_mcast(s, f); -#endif - } 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 -#ifdef PICO_SUPPORT_MCAST -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; - } - - pico_enqueue_and_wakeup_if_needed(&s->q_in, s, cpy); - } - - return 0; -} -#endif -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))) { -#ifdef PICO_SUPPORT_MCAST - int retval = pico_socket_udp_deliver_ipv6_mcast(s, f); - pico_frame_discard(f); - return retval; -#endif - } - 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; - } - - pico_enqueue_and_wakeup_if_needed(&s->q_in, s, cpy); - } - - 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 cb60650..0000000 --- a/ext/picotcp/modules/pico_strings.c +++ /dev/null @@ -1,101 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015-2017 Altran ISY BeNeLux. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 0; -} - -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 c4b6ac2..0000000 --- a/ext/picotcp/modules/pico_strings.h +++ /dev/null @@ -1,21 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015-2017 Altran ISY BeNeLux. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 df1c9ea..0000000 --- a/ext/picotcp/modules/pico_tcp.c +++ /dev/null @@ -1,3307 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_socket_tcp.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 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 - -#ifdef DEBUG_TCP_GENERAL -#define tcp_dbg dbg -#else -#define tcp_dbg(...) do {} while(0) -#endif - -#ifdef DEBUG_TCP_NAGLE -#define tcp_dbg_nagle dbg -#else -#define tcp_dbg_nagle(...) do {} while(0) -#endif - -#ifdef DEBUG_TCP_OPTIONS -#define tcp_dbg_options dbg -#else -#define tcp_dbg_options(...) do {} while(0) -#endif - -#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; - - if (!f->payload_len) - return NULL; - - seg = PICO_ZALLOC(sizeof(struct tcp_input_segment)); - if (!seg) - 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); - if (!pico_timer_add(2000, sock_stats, t)) { - tcp_dbg("TCP: Failed to start socket statistics timer\n"); - } -} -#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 * (pico_time)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); - if (!t->keepalive_tmr) { - tcp_dbg("TCP: Failed to start keepalive timer\n"); - if (t->sock.wakeup) - t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); - } -} - -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 - if (!pico_timer_add(2000, sock_stats, t)) { - tcp_dbg("TCP: Failed to start socket statistics timer\n"); - PICO_FREE(t); - return NULL; - } -#endif - - t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t); - if (!t->keepalive_tmr) { - tcp_dbg("TCP: Failed to start keepalive timer\n"); - PICO_FREE(t); - return NULL; - } - 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, NULL, (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); - ts->retrans_tmr = pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts); - if (!ts->retrans_tmr) { - tcp_dbg("TCP: Failed to start initconn_retry timer\n"); - PICO_FREE(syn); - return -1; - } - pico_enqueue(&tcp_out, syn); - 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, NULL, (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, NULL, (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, NULL, (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, NULL, 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, NULL, (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); - if (!t->fin_tmr) { - tcp_dbg("TCP: failed to start delete callback timer, deleting socket now\n"); - tcp_deltcb((pico_time)0, 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, NULL, (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); - if(!t->retrans_tmr) { - tcp_dbg("TCP: Failed to start retransmission timer\n"); - //TODO do something about this? - } else { - 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; - uint32_t rtt = 0; - uint16_t acked = 0; - pico_time acked_timestamp = 0; - struct pico_frame *una = NULL; - - if (!f || !s) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - - 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->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 - if (!pico_timer_add(2000, sock_stats, s)) { - tcp_dbg("TCP: Failed to start socket statistics timer\n"); - return -1; - } -#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; - mtu = (uint16_t)pico_socket_get_mss(&new->sock); - new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR); - tcp_parse_options(f); - 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_FIN, &(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, get_sock_dev(&t->sock), (uint16_t) (size1 + overhead)); - f2 = pico_socket_frame_alloc(&t->sock, get_sock_dev(&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... */ - if (pico_enqueue_segment(&t->tcpq_out, f2) < 0) { - tcp_dbg("Discarding invalid segment\n"); - pico_frame_discard(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, get_sock_dev(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 784a6bd..0000000 --- a/ext/picotcp/modules/pico_tcp.h +++ /dev/null @@ -1,106 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 e20a06c..0000000 --- a/ext/picotcp/modules/pico_tftp.c +++ /dev/null @@ -1,1323 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ - -#include -#include -#include -#include -#include - -#ifdef DEBUG_TFTP -#define tftp_dbg dbg -#else -#define tftp_dbg(...) do {} while(0) -#endif - -/* 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_finish(struct pico_tftp_session *session); - -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); - if (!session->timer) { - tftp_dbg("TFTP: Failed to start callback timer, deleting session\n"); - tftp_finish(session); - return; - } - session->active_timers++; - } - } else { - session->timer = pico_timer_add(interval + 1, timer_callback, session); - if (!session->timer) { - tftp_dbg("TFTP: Failed to start callback timer, deleting session\n"); - tftp_finish(session); - return; - } - 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 2785189..0000000 --- a/ext/picotcp/modules/pico_tftp.h +++ /dev/null @@ -1,83 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 6d3ba72..0000000 --- a/ext/picotcp/modules/pico_udp.c +++ /dev/null @@ -1,222 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" - -#ifdef DEBUG_UDP -#define udp_dbg dbg -#else -#define udp_dbg(...) do {} while(0) -#endif - -#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame)) - -/* 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 7c5814e..0000000 --- a/ext/picotcp/modules/pico_udp.h +++ /dev/null @@ -1,45 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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/6lowpan.mk b/ext/picotcp/rules/6lowpan.mk deleted file mode 100644 index 58bbf69..0000000 --- a/ext/picotcp/rules/6lowpan.mk +++ /dev/null @@ -1,62 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_6LOWPAN -DPICO_SUPPORT_IPV6 - -################################################################################ -# DEFAULTS -################################################################################ - -# Enable the 6LoWPAN IPHC compression scheme by default -6LOWPAN_IPHC?=1 - -# Disable MAC framing for mac-enabled radios, disabled by default -6LOWPAN_NOMAC?=0 - -# Enable IEEE802.15.4 device support by default -IEEE802154?=1 - -# Enable radiotest packet dump -RADIOTEST_PCAP?=0 - -################################################################################ -# 6LOWPAN OPTIONS -################################################################################ - -ifeq ($(6LOWPAN_IPHC), 1) - EXTRA_CFLAGS+=-DPICO_6LOWPAN_IPHC_ENABLED -endif - -ifeq ($(6LOWPAN_NOMAC), 1) - EXTRA_CFLAGS+=-DPICO_6LOWPAN_NOMAC -endif - -################################################################################ -# 6LOWPAN LINK LAYER OPTIONS -################################################################################ - -# IEEE802.15.4 with or without mac layer -ifeq ($(IEEE802154), 1) - 6LOWPAN_OPTIONS+=-DPICO_SUPPORT_802154 - POSIX_OBJ+=modules/pico_dev_radiotest.o \ - modules/pico_dev_radio_mgr.o -endif - -OPTIONS+=$(6LOWPAN_OPTIONS) - -# Append module objects -MOD_OBJ+=$(LIBBASE)modules/pico_6lowpan_ll.o -MOD_OBJ+=$(LIBBASE)modules/pico_6lowpan.o -MOD_OBJ+=$(LIBBASE)modules/pico_802154.o - -# Count the amount of supported 6LoWPAN Link Layer protocols based on the amount of words in -# $6LOWPAN_OPTIONS. This allows us to define a static array that can be initialized with the 6LoWPAN -# link layer protocol definitions for the supported link layer protocols. This happens upon -# initialization of the 6LoWPAN_LL-layer. -EXTRA_CFLAGS+=-DPICO_6LOWPAN_LLS=$(words $(6LOWPAN_OPTIONS)) - -################################################################################ -# RADIOTEST -################################################################################ - -ifeq ($(RADIOTEST_PCAP), 1) - EXTRA_CFLAGS+=-DRADIO_PCAP - TEST_LDFLAGS+=-lpcap -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/debug.mk b/ext/picotcp/rules/debug.mk deleted file mode 100644 index 481c45d..0000000 --- a/ext/picotcp/rules/debug.mk +++ /dev/null @@ -1,207 +0,0 @@ -DEBUG_ALL?=0 - -DEBUG_ARP?=0 -DEBUG_AODV?=0 -DEBUG_PPP?=0 -DEBUG_TAP_ALL?=0 -DEBUG_TAP_GENERAL?=0 -DEBUG_TAP_INFO?=0 -DEBUG_TAP_WIN?=0 -DEBUG_TAP_REG?=0 -DEBUG_DHCP_CLIENT?=0 -DEBUG_DHCP_SERVER?=0 -DEBUG_DNS?=0 -DEBUG_DNS_SD?=0 -DEBUG_FRAG?=0 -DEBUG_IGMP?=0 -DEBUG_IPF?=0 -DEBUG_MCAST?=0 -DEBUG_IPV6?=0 -DEBUG_IPV6_ROUTE?=0 -DEBUG_IPV6_ND?=0 -DEBUG_MDNS?=0 -DEBUG_MLD?=0 -DEBUG_MM?=0 -DEBUG_NAT?=0 -DEBUG_OLSR?=0 -DEBUG_SLAACV4?=0 -DEBUG_SNTP?=0 -DEBUG_TCP_ALL?=0 -DEBUG_TCP_NAGLE?=0 -DEBUG_TCP_OPTIONS?=0 -DEBUG_TCP_GENERAL?=0 -DEBUG_TFTP?=0 -DEBUG_UDP?=0 -DEBUG_6LOWPAN?=0 -DEBUG_RADIOTEST?=0 - -ifneq ($(DEBUG_ALL),0) - DEBUG_ARP=1 - DEBUG_AODV=1 - DEBUG_PPP=1 - DEBUG_TAP_ALL=1 - DEBUG_DHCP_CLIENT=1 - DEBUG_DHCP_SERVER=1 - DEBUG_DNS=1 - DEBUG_DNS_SD=1 - DEBUG_FRAG=1 - DEBUG_IGMP=1 - DEBUG_IPF=1 - DEBUG_MCAST=1 - DEBUG_IPV6=1 - DEBUG_IPV6_ROUTE=1 - DEBUG_IPV6_ND=1 - DEBUG_MDNS=1 - DEBUG_MLD=1 - DEBUG_MM=1 - DEBUG_NAT=1 - DEBUG_OLSR=1 - DEBUG_SLAACV4=1 - DEBUG_SNTP=1 - DEBUG_TCP_ALL=1 - DEBUG_TFTP=1 - DEBUG_UDP=1 - DEBUG_6LOWPAN=1 - DEBUG_RADIOTEST=1 -endif - -ifneq ($(DEBUG_TCP_ALL),0) - DEBUG_TCP_NAGLE=1 - DEBUG_TCP_OPTIONS=1 - DEBUG_TCP_GENERAL=1 -endif - -ifneq ($(DEBUG_TAP_ALL),0) - DEBUG_TAP_GENERAL=1 - DEBUG_TAP_INFO=1 - DEBUG_TAP_WIN=1 - DEBUG_TAP_REG=1 -endif - -ifneq ($(DEBUG_ARP),0) - CFLAGS+=-DDEBUG_ARP -endif - -ifneq ($(DEBUG_AODV),0) - CFLAGS+=-DDEBUG_AODV -endif - -ifneq ($(DEBUG_PPP),0) - CFLAGS+=-DDEBUG_PPP -endif - -ifneq ($(DEBUG_TAP_GENERAL),0) - CFLAGS+=-DDEBUG_TAP_GENERAL -endif - -ifneq ($(DEBUG_TAP_INFO),0) - CFLAGS+=-DDEBUG_TAP_INFO -endif - -ifneq ($(DEBUG_TAP_WIN),0) - CFLAGS+=-DDEBUG_TAP_WIN -endif - -ifneq ($(DEBUG_TAP_REG),0) - CFLAGS+=-DDEBUG_TAP_REG -endif - -ifneq ($(DEBUG_DHCP_CLIENT),0) - CFLAGS+=-DDEBUG_DHCP_CLIENT -endif - -ifneq ($(DEBUG_DHCP_SERVER),0) - CFLAGS+=-DDEBUG_DHCP_SERVER -endif - -ifneq ($(DEBUG_DNS),0) - CFLAGS+=-DDEBUG_DNS -endif - -ifneq ($(DEBUG_DNS_SD),0) - CFLAGS+=-DDEBUG_DNS_SD -endif - -ifneq ($(DEBUG_FRAG),0) - CFLAGS+=-DDEBUG_FRAG -endif - -ifneq ($(DEBUG_IGMP),0) - CFLAGS+=-DDEBUG_IGMP -endif - -ifneq ($(DEBUG_IPF),0) - CFLAGS+=-DDEBUG_IPF -endif - -ifneq ($(DEBUG_MCAST),0) - CFLAGS+=-DDEBUG_MCAST -endif - -ifneq ($(DEBUG_IPV6),0) - CFLAGS+=-DDEBUG_IPV6 -endif - -ifneq ($(DEBUG_IPV6_ROUTE),0) - CFLAGS+=-DDEBUG_IPV6_ROUTE -endif - -ifneq ($(DEBUG_IPV6_ND),0) - CFLAGS+=-DDEBUG_IPV6_ND -endif - -ifneq ($(DEBUG_MDNS),0) - CFLAGS+=-DDEBUG_MDNS -endif - -ifneq ($(DEBUG_MLD),0) - CFLAGS+=-DDEBUG_MLD -endif - -ifneq ($(DEBUG_MM),0) - CFLAGS+=-DDEBUG_MM -endif - -ifneq ($(DEBUG_NAT),0) - CFLAGS+=-DDEBUG_NAT -endif - -ifneq ($(DEBUG_OLSR),0) - CFLAGS+=-DDEBUG_OLSR -endif - -ifneq ($(DEBUG_SLAACV4),0) - CFLAGS+=-DDEBUG_SLAACV4 -endif - -ifneq ($(DEBUG_SNTP),0) - CFLAGS+=-DDEBUG_SNTP -endif - -ifneq ($(DEBUG_TCP_NAGLE),0) - CFLAGS+=-DDEBUG_TCP_NAGLE -endif - -ifneq ($(DEBUG_TCP_OPTIONS),0) - CFLAGS+=-DDEBUG_TCP_OPTIONS -endif - -ifneq ($(DEBUG_TCP_GENERAL),0) - CFLAGS+=-DDEBUG_TCP_GENERAL -endif - -ifneq ($(DEBUG_TFTP),0) - CFLAGS+=-DDEBUG_TFTP -endif - -ifneq ($(DEBUG_UDP),0) - CFLAGS+=-DDEBUG_UDP -endif - -ifneq ($(DEBUG_6LOWPAN),0) - CFLAGS+=-DDEBUG_6LOWPAN -endif - -ifneq ($(DEBUG_RADIOTEST), 0) - CFLAGS+=-DDEBUG_RADIOTEST -endif 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 50b598a..0000000 --- a/ext/picotcp/rules/eth.mk +++ /dev/null @@ -1,3 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_ETH -MOD_OBJ+=$(LIBBASE)modules/pico_arp.o -MOD_OBJ+=$(LIBBASE)modules/pico_ethernet.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/ipc.mk b/ext/picotcp/rules/ipc.mk deleted file mode 100644 index 61c5ed2..0000000 --- a/ext/picotcp/rules/ipc.mk +++ /dev/null @@ -1 +0,0 @@ -MOD_OBJ+=$(LIBBASE)modules/pico_dev_ipc.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 5628a7b..0000000 --- a/ext/picotcp/rules/mcast.mk +++ /dev/null @@ -1,2 +0,0 @@ -OPTIONS+=-DPICO_SUPPORT_MCAST -MOD_OBJ+=$(LIBBASE)modules/pico_mcast.o 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 4d06f1a..0000000 --- a/ext/picotcp/stack/pico_device.c +++ /dev/null @@ -1,482 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" -#include "pico_802154.h" -#include "pico_6lowpan.h" -#include "pico_6lowpan_ll.h" -#include "pico_addressing.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_6LOWPAN -static struct pico_ipv6_link * pico_6lowpan_link_add(struct pico_device *dev, const struct pico_ip6 *prefix) -{ - struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - struct pico_6lowpan_info *info = (struct pico_6lowpan_info *)dev->eth; - struct pico_ipv6_link *link = NULL; /* Make sure to return NULL */ - struct pico_ip6 newaddr; - - memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6); - memcpy(newaddr.addr + 8, info->addr_ext.addr, SIZE_6LOWPAN_EXT); - newaddr.addr[8] = newaddr.addr[8] ^ 0x02; /* Toggle U/L bit */ - - /* RFC6775: No Duplicate Address Detection (DAD) is performed if - * EUI-64-based IPv6 addresses are used (as these addresses are assumed - * to be globally unique). */ - if ((link = pico_ipv6_link_add_no_dad(dev, newaddr, netmask64))) { - if (pico_ipv6_is_linklocal(newaddr.addr)) - pico_6lp_nd_start_soliciting(link, NULL); - else - pico_6lp_nd_register(link); - } - - return link; -} - -static int pico_6lowpan_store_info(struct pico_device *dev, const uint8_t *mac) -{ - if ((dev->eth = PICO_ZALLOC(sizeof(struct pico_6lowpan_info)))) { - memcpy(dev->eth, mac, sizeof(struct pico_6lowpan_info)); - return 0; - } else { - pico_err = PICO_ERR_ENOMEM; - return -1; - } -} -#endif - -#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, NULL); - 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 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - struct pico_ipv6_link *link = NULL; /* Make sure to return NULL */ - struct pico_ip6 newaddr; - - if (0) {} -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(dev)) { - link = pico_6lowpan_link_add(dev, prefix); - } -#endif - else { - 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]; - if ((link = pico_ipv6_link_add(dev, newaddr, netmask64))) { - device_init_ipv6_final(dev, &newaddr); - } - } - - return link; -} -#endif -static int device_init_mac(struct pico_device *dev, const 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 - - if (0) {} -#ifdef PICO_SUPPORT_6LOWPAN - else if (PICO_DEV_IS_6LOWPAN(dev)) { - if (pico_6lowpan_store_info(dev, mac)) - return -1; - } -#endif - else { - if ((dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev)))) { - memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH); - } else { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - } - -#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 - - 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; -} - -#define DEBUG_IPV6(ip) { \ - char ipstr[40] = { 0 }; \ - pico_ipv6_to_string(ipstr, (ip).addr); \ - dbg("IPv6 (%s)\n", ipstr); \ - } - -int pico_device_init(struct pico_device *dev, const char *name, const 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; - } - - if (pico_tree_insert(&Device_tree, dev)) { - PICO_FREE(dev->q_in); - PICO_FREE(dev->q_out); - return -1; - } - if (!dev->mtu) - dev->mtu = PICO_DEVICE_DEFAULT_MTU; - -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(dev) && LL_MODE_ETHERNET == dev->mode) - return -1; -#endif - - if (mac) { - ret = device_init_mac(dev, mac); - } else { - if (!dev->mode) { - ret = device_init_nomac(dev); - } -#ifdef PICO_SUPPORT_6LOWPAN - else { - /* RFC6775: Link Local to be formed based on EUI-64 as per RFC6775 */ - dbg("Link local address to be formed based on EUI-64\n"); - return -1; - } -#endif - } - 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->mode && 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) { - pico_datalink_receive(f); - loop_score--; - } - } - return loop_score; -} - -static int devloop_sendto_dev(struct pico_device *dev, struct pico_frame *f) -{ -#ifdef PICO_SUPPORT_6LOWPAN - if (PICO_DEV_IS_6LOWPAN(dev)) { - return (pico_6lowpan_ll_sendto_dev(dev, f) <= 0); - } -#endif - return (dev->send(dev, f->start, (int)f->len) <= 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 7aad7f3..0000000 --- a/ext/picotcp/stack/pico_frame.c +++ /dev/null @@ -1,329 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - -#include "pico_config.h" -#include "pico_frame.h" -#include "pico_protocol.h" -#include "pico_stack.h" -#include "pico_socket.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((size_t)frame_buffer_size + sizeof(uint32_t)); - if (!p->buffer) { - PICO_FREE(p); - return NULL; - } - - p->usage_count = (uint32_t *)(((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; - p->net_hdr = p->buffer; - p->datalink_hdr = p->buffer; - p->transport_hdr = p->buffer; - p->app_hdr = p->buffer; - p->payload = p->buffer; - - 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); -} - -static uint8_t * -pico_frame_new_buffer(struct pico_frame *f, uint32_t size, uint32_t *oldsize) -{ - uint8_t *oldbuf; - uint32_t usage_count, *p_old_usage; - uint32_t frame_buffer_size; - unsigned int align; - - if (!f || (size < f->buffer_len)) { - return NULL; - } - - 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((size_t)frame_buffer_size + sizeof(uint32_t)); - if (!f->buffer) { - f->buffer = oldbuf; - return NULL; - } - - f->usage_count = (uint32_t *)(((uint8_t*)f->buffer) + frame_buffer_size); - *f->usage_count = usage_count; - f->buffer_len = size; - - if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER) - PICO_FREE(p_old_usage); - /* Now, the frame is not zerocopy anymore, and the usage counter has been moved within it */ - return oldbuf; -} - -static int -pico_frame_update_pointers(struct pico_frame *f, ptrdiff_t addr_diff, uint8_t *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_BUFFER)) - PICO_FREE(oldbuf); - else if (f->notify_free) - f->notify_free(oldbuf); - - f->flags = 0; - return 0; -} - -int pico_frame_grow_head(struct pico_frame *f, uint32_t size) -{ - ptrdiff_t addr_diff = 0; - uint32_t oldsize = 0; - uint8_t *oldbuf = pico_frame_new_buffer(f, size, &oldsize); - if (!oldbuf) - return -1; - - /* Put old buffer at the end of new buffer */ - memcpy(f->buffer + f->buffer_len - oldsize, oldbuf, (size_t)oldsize); - addr_diff = (ptrdiff_t)(f->buffer + f->buffer_len - oldsize - oldbuf); - - return pico_frame_update_pointers(f, addr_diff, oldbuf); -} - -int pico_frame_grow(struct pico_frame *f, uint32_t size) -{ - ptrdiff_t addr_diff = 0; - uint32_t oldsize = 0; - uint8_t *oldbuf = pico_frame_new_buffer(f, size, &oldsize); - if (!oldbuf) - return -1; - - /* Just put old buffer at the beginning of new buffer */ - memcpy(f->buffer, oldbuf, (size_t)oldsize); - addr_diff = (ptrdiff_t)(f->buffer - oldbuf); - - return pico_frame_update_pointers(f, addr_diff, oldbuf); -} - -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); - ptrdiff_t 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 = (ptrdiff_t)(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; - - if (f->info) { - new->info = PICO_ZALLOC(sizeof(struct pico_remote_endpoint)); - if (!new->info) { - pico_frame_discard(new); - return NULL; - } - memcpy(new->info, f->info, sizeof(struct pico_remote_endpoint)); - } - -#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 *)(((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 2c235be..0000000 --- a/ext/picotcp/stack/pico_md5.c +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************* - * PicoTCP. Copyright (c) 2015-2017 Altran Intelligent Systems. Some rights reserved. - * See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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 c301c0a..0000000 --- a/ext/picotcp/stack/pico_protocol.c +++ /dev/null @@ -1,227 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - - . - - Authors: Daniele Lacamera - *********************************************************************/ - - -#include "pico_protocol.h" -#include "pico_tree.h" -#include "../../../include/libztDebug.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; -} - -static PICO_TREE_DECLARE(Datalink_proto_tree, pico_proto_cmp); -static PICO_TREE_DECLARE(Network_proto_tree, pico_proto_cmp); -static PICO_TREE_DECLARE(Transport_proto_tree, pico_proto_cmp); -static 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) -{ - struct pico_tree *tree = NULL; - struct pico_proto_rr *proto = NULL; - - if (!p) - return; - - p->hash = pico_hash(p->name, (uint32_t)strlen(p->name)); - switch (p->layer) { - case PICO_LAYER_DATALINK: - tree = &Datalink_proto_tree; - proto = &proto_rr_datalink; - break; - case PICO_LAYER_NETWORK: - tree = &Network_proto_tree; - proto = &proto_rr_network; - break; - case PICO_LAYER_TRANSPORT: - tree = &Transport_proto_tree; - proto = &proto_rr_transport; - break; - case PICO_LAYER_SOCKET: - tree = &Socket_proto_tree; - proto = &proto_rr_socket; - break; - default: - DEBUG_EXTRA("Unknown protocol: %s (layer: %d)", p->name, p->layer); - return; - } - - if (pico_tree_insert(tree, p)) { - DEBUG_EXTRA("Failed to insert protocol %s", p->name); - return; - } - - proto_layer_rr_reset(proto); - DEBUG_EXTRA("Protocol %s registered (layer: %d).", 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 145442f..0000000 --- a/ext/picotcp/stack/pico_socket.c +++ /dev/null @@ -1,2289 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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" - -#include "../../../include/libztDebug.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 - -/* Mockables */ -#if defined UNIT_TEST -# define MOCKABLE __attribute__((weak)) -#else -# define MOCKABLE -#endif - -#define PROTO(s) ((s)->proto->proto_number) - -#define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */ - -#ifdef PICO_SUPPORT_IPV4FRAG - -#ifdef DEBUG_FRAG -#define frag_dbg dbg -#else -#define frag_dbg(...) do {} while(0) -#endif - -#endif - -static struct pico_sockport *sp_udp = NULL, *sp_tcp = NULL; - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, struct pico_device *dev, 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 ret; -} - -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; -} - -static PICO_TREE_DECLARE(UDPTable, sockport_cmp); -static 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; - if (PROTO(s) != PICO_PROTO_UDP && PROTO(s) != PICO_PROTO_TCP) - { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - 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) - { - if (pico_tree_insert(&UDPTable, sp)) { - PICO_FREE(sp); - PICOTCP_MUTEX_UNLOCK(Mutex); - return -1; - } - - } - else if (PROTO(s) == PICO_PROTO_TCP) - { - if (pico_tree_insert(&TCPTable, sp)) { - PICO_FREE(sp); - PICOTCP_MUTEX_UNLOCK(Mutex); - return -1; - } - } - } - - if (pico_tree_insert(&sp->socks, s)) { - PICOTCP_MUTEX_UNLOCK(Mutex); - return -1; - } - s->state |= PICO_SOCKET_STATE_BOUND; - PICOTCP_MUTEX_UNLOCK(Mutex); -#ifdef DEBUG_SOCKET_TREE - { - struct pico_tree_node *index; - 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); -#ifdef PICO_SUPPORT_MCAST - pico_multicast_delete(s); -#endif - pico_socket_tcp_delete(s); - s->state = PICO_SOCKET_STATE_CLOSED; - if (!pico_timer_add((pico_time)10, socket_garbage_collect, s)) { - dbg("SOCKET: Failed to start garbage collect timer, doing garbage collection now\n"); - PICOTCP_MUTEX_UNLOCK(Mutex); - socket_garbage_collect((pico_time)0, s); - return -1; - } - 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) { - // DEBUG_EXTRA("No such port %d", 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; - -} - -extern struct pico_socket *MOCKABLE 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; -} - -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); - } -} - -extern 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; - struct pico_device *dev = NULL; - uint16_t hdr_offset = (uint16_t)pico_socket_sendto_transport_offset(s); - int ret = 0; - (void)src; - - if (msginfo) { - dev = msginfo->dev; - } -#ifdef PICO_SUPPORT_IPV6 - else if (IS_SOCK_IPV6(s) && ep && pico_ipv6_is_multicast(&ep->remote_addr.ip6.addr[0])) { - dev = pico_ipv6_link_find(src); - } -#endif - else if (IS_SOCK_IPV6(s) && ep) { - dev = pico_ipv6_source_dev_find(&ep->remote_addr.ip6); - } else if (IS_SOCK_IPV4(s) && ep) { - dev = pico_ipv4_source_dev_find(&ep->remote_addr.ip4); - } else { - dev = get_sock_dev(s); - } - - if (!dev) { - return -1; - } - - f = pico_socket_frame_alloc(s, dev, (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; - } - - 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 < 0) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - pico_endpoint_free(ep); - return -1; - } - - 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, get_sock_dev(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 -} - -struct pico_device *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 - - return s->dev; -} - - -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; -} - -extern int MOCKABLE 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 MOCKABLE 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); -} - - -extern 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 - -extern 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; -} - -extern 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 MOCKABLE 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; -} - -extern 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)) { - //DEBUG_EXTRA("Socket not found..."); - 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, struct pico_device *dev, 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, dev, len); - -#endif - -#ifdef PICO_SUPPORT_IPV4 - if (is_sock_ipv4(s)) - f = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, 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 8e69e45..0000000 --- a/ext/picotcp/stack/pico_socket_multicast.c +++ /dev/null @@ -1,1478 +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 - -#ifdef DEBUG_MCAST -#define so_mcast_dbg dbg -#else -#define so_mcast_dbg(...) do { } while(0) -#endif - -/* 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 -{ - int8_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 */ -static 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 */ -static 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 */ -static 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 int8_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 int8_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 int8_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) { - if ((void *)source == (void *)&LEAF) - return -1; - else - 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) { - if ((void *)source == (void *)&LEAF) - return -1; - else - pico_tree_delete(&MCASTFilter_ipv6, source); - } - } - } - -#endif - return PICO_IP_MULTICAST_EXCLUDE; -} - -static int8_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; - if (pico_tree_insert(&MCASTFilter, source) == &LEAF) - return -1; - } - } - -#ifdef PICO_SUPPORT_IPV6 - if( !pico_tree_empty(&listen->MCASTSources_ipv6)) { - pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp) - { - source = index->keyValue; - if (pico_tree_insert(&MCASTFilter_ipv6, source) == &LEAF) - return -1; - } - } - -#endif - return PICO_IP_MULTICAST_INCLUDE; -} - -struct pico_mcast_filter_aggregation -{ - int8_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(int8_t fm, struct pico_mcast_listen *l) -{ - if (!l) - return -1; - - if (fm > 1 || fm < 0) - 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) -{ - int8_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 || filter_mode < 0) - 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 = index2->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; - if (pico_tree_insert(listen_tree, mcast.listen)) { - PICO_FREE(mcast.listen); - return -1; - } - - if (pico_tree_insert(&MCASTSockets, s) == &LEAF) { - pico_tree_delete(listen_tree, mcast.listen); - PICO_FREE(mcast.listen); - return -1; - } - - 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)) { - if (pico_tree_insert(&mcast.listen->MCASTSources, source)) { - PICO_FREE(source); - return -1; - } - } - -#ifdef PICO_SUPPORT_IPV6 - else if( IS_SOCK_IPV6(s)) - if (pico_tree_insert(&mcast.listen->MCASTSources_ipv6, source)) { - PICO_FREE(source); - return -1; - } -#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_EADDRNOTAVAIL; - 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 (pico_tree_insert(tree, source)) { - PICO_FREE(source); - return -1; - } - - } 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; - if (pico_tree_insert(tree, source)) { - PICO_FREE(mcast.listen); - PICO_FREE(source); - return -1; - } - - if (pico_tree_insert(listen_tree, mcast.listen)) { - pico_tree_delete(tree, source); - PICO_FREE(source); - PICO_FREE(mcast.listen); - return -1; - } - reference_count = 1; - } - - if (pico_tree_insert(&MCASTSockets, s) == &LEAF) { - return -1; - } - - 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 3e21115..0000000 --- a/ext/picotcp/stack/pico_stack.c +++ /dev/null @@ -1,969 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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_6lowpan_ll.h" -#include "pico_ethernet.h" -#include "pico_6lowpan.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" - -#include "../../../include/libztDebug.h" - -/* Mockables */ -#if defined UNIT_TEST -# define MOCKABLE __attribute__((weak)) -#else -# define MOCKABLE -#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; -} - -/******************************************************************************* - * NETWORK LAYER - ******************************************************************************/ - -MOCKABLE 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; -} - -/// 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; -} - -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; -} - -/******************************************************************************* - * DATALINK LAYER - ******************************************************************************/ - -int pico_datalink_receive(struct pico_frame *f) -{ - if (f->dev->eth) { - /* If device has stack with datalink-layer pass frame through it */ - switch (f->dev->mode) { - #ifdef PICO_SUPPORT_802154 - case LL_MODE_IEEE802154: - f->datalink_hdr = f->buffer; - return pico_enqueue(pico_proto_6lowpan_ll.q_in, f); - #endif - default: - #ifdef PICO_SUPPORT_ETH - f->datalink_hdr = f->buffer; - return pico_enqueue(pico_proto_ethernet.q_in,f); - #else - return -1; - #endif - } - } else { - /* If device handles raw IP-frames send it straight to network-layer */ - f->net_hdr = f->buffer; - pico_network_receive(f); - } - - return 0; -} - -MOCKABLE int pico_datalink_send(struct pico_frame *f) -{ - if (f->dev->eth) { - switch (f->dev->mode) { - #ifdef PICO_SUPPORT_802154 - case LL_MODE_IEEE802154: - return pico_enqueue(pico_proto_6lowpan.q_out, f); - #endif - default: - #ifdef PICO_SUPPORT_ETH - return pico_enqueue(pico_proto_ethernet.q_out, f); - #else - return -1; - #endif - } - } else { - /* non-ethernet: no post-processing needed */ - return pico_sendto_dev(f); - } -} - -/******************************************************************************* - * PHYSICAL LAYER - ******************************************************************************/ - -struct pico_frame *pico_stack_recv_new_frame(struct pico_device *dev, uint8_t *buffer, uint32_t len) -{ - struct pico_frame *f; - if (len == 0) - return NULL; - - f = pico_frame_alloc(len); - if (!f) - { - dbg("Cannot alloc incoming frame!\n"); - return NULL; - } - - /* 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); - return 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. - */ -int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len) -{ - struct pico_frame *f = pico_stack_recv_new_frame (dev, buffer, len); - int32_t ret; - - if (!f) - return -1; - - 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; - uint32_t hash; - 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; -} - -extern int pico_ntimers() -{ - return Timers->n; -} - -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); - } - - 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; - if (id == 0u) - return; - - for (i = 1; i <= Timers->n; i++) { - tref = heap_get_element(Timers, i); - if (tref->id == id) { - if (tref->tmr) - { - PICO_FREE(tref->tmr); - tref->tmr = NULL; - tref->id = 0; - } - break; - } - } -} - -void pico_timer_cancel_hashed(uint32_t hash) -{ - uint32_t i; - struct pico_timer_ref *tref; - if (hash == 0u) - return; - - for (i = 1; i <= Timers->n; i++) { - tref = heap_get_element(Timers, i); - if (tref->hash == hash) { - if (tref->tmr) - { - PICO_FREE(tref->tmr); - tref->tmr = NULL; - tref[i].id = 0; - } - } - } -} - -#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; -} - -extern 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(); - } -} - -static uint32_t -pico_timer_ref_add(pico_time expire, struct pico_timer *t, uint32_t id, uint32_t hash) -{ - struct pico_timer_ref tref; - - tref.expire = PICO_TIME_MS() + expire; - tref.tmr = t; - tref.id = id; - tref.hash = hash; - - if (heap_insert(Timers, &tref) < 0) { - DEBUG_ERROR("Error: failed to insert timer(ID %u) into heap", id); - PICO_FREE(t); - pico_err = PICO_ERR_ENOMEM; - return 0; - } - if (Timers->n > PICO_MAX_TIMERS) { - DEBUG_ERROR("Warning: I have %d timers", (int)Timers->n); - } - - return tref.id; -} - -static struct pico_timer * -pico_timer_create(void (*timer)(pico_time, void *), void *arg) -{ - struct pico_timer *t = PICO_ZALLOC(sizeof(struct pico_timer)); - - if (!t) { - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - t->arg = arg; - t->timer = timer; - - return t; -} - -MOCKABLE uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - struct pico_timer *t = pico_timer_create(timer, arg); - - /* zero is guard for timers */ - if (tmr_id == 0u) { - tmr_id++; - } - - if (!t) - return 0; - - return pico_timer_ref_add(expire, t, tmr_id++, 0); -} - -uint32_t pico_timer_add_hashed(pico_time expire, void (*timer)(pico_time, void *), void *arg, uint32_t hash) -{ - struct pico_timer *t = pico_timer_create(timer, arg); - - /* zero is guard for timers */ - if (tmr_id == 0u) { - tmr_id++; - } - - if (!t) - return 0; - - return pico_timer_ref_add(expire, t, tmr_id++, hash); -} /* Static path count: 4 */ - -extern int MOCKABLE pico_stack_init(void) -{ -#ifdef PICO_SUPPORT_ETH - pico_protocol_init(&pico_proto_ethernet); -#endif - -#ifdef PICO_SUPPORT_6LOWPAN - pico_protocol_init(&pico_proto_6lowpan); - pico_protocol_init(&pico_proto_6lowpan_ll); -#endif - -#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 -#ifdef PICO_SUPPORT_6LOWPAN - if (pico_6lowpan_init()) - return -1; -#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 8955696..0000000 --- a/ext/picotcp/stack/pico_tree.c +++ /dev/null @@ -1,565 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 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); -} - -static void pico_tree_insert_node(struct pico_tree *tree, struct pico_tree_node *insert) -{ - struct pico_tree_node *temp = tree->root; - struct pico_tree_node *last_node = INIT_LEAF; - int result = 0; - - /* 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; - } -} - -void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator) -{ - struct pico_tree_node *insert; - void *LocalKey; - - LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree, key) : NULL); - - /* if node already in, bail out */ - if(LocalKey) { - pico_err = PICO_ERR_EEXIST; - return LocalKey; - } - - insert = create_node(tree, key, allocator); - - if(!insert) - { - pico_err = PICO_ERR_ENOMEM; - /* to let the user know that it couldn't insert */ - return (void *)&LEAF; - } - - pico_tree_insert_node(tree, 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 = pico_tree_findNode(tree, key); - if (found == NULL) - return NULL; - return found->keyValue; -} - -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(AM_I_LEFT_CHILD(node)) { - 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/test/Makefile b/ext/picotcp/test/Makefile deleted file mode 100644 index 038d1e6..0000000 --- a/ext/picotcp/test/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -CC=gcc -CFLAGS=-ggdb -I../build/include/ -L../build/lib/ -lpicotcp -lvdeplug -APPNAME=test_tftp_app_client - -.PHONY: clean -all: test_tftp_app_client -test_tftp_app_client: test_tftp_app_client.o - $(CC) -o test_tftp_app_client ../build/modules/pico_dev_vde.o $^ $(CFLAGS) -clean: - rm -f ${APPNAME}.o diff --git a/ext/picotcp/test/README.md b/ext/picotcp/test/README.md deleted file mode 100644 index 0e284ff..0000000 --- a/ext/picotcp/test/README.md +++ /dev/null @@ -1,6 +0,0 @@ -To run these tests on your linux system, you will have to install these dependencies: -* vde2 -* libvdeplug2-dev -* libpcap0.8-dev - -This will allow you to compile the 'make test' and run the tests diff --git a/ext/picotcp/test/autotest.sh b/ext/picotcp/test/autotest.sh deleted file mode 100755 index 407b042..0000000 --- a/ext/picotcp/test/autotest.sh +++ /dev/null @@ -1,360 +0,0 @@ -#!/bin/bash - -TFTP_EXEC_DIR="$(pwd)/build/test" -TFTP_WORK_DIR="${TFTP_EXEC_DIR}/tmp" -TFTP_WORK_SUBDIR="${TFTP_WORK_DIR}/subdir" -TFTP_WORK_FILE="test.img" - - - -function tftp_setup() { - dd if=/dev/urandom bs=1000 count=10 of=${1}/$TFTP_WORK_FILE -} - -function tftp_cleanup() { - echo CLEANUP - pwd;ls - killall -wq picoapp.elf - rm -rf $TFTP_WORK_DIR - if [ $1 ]; then - exit $1 - fi -} - -if ! [ -x "$(command -v vde_switch)" ]; then - echo 'VDE Switch is not installed.' >&2 -fi - -if [ ! -e test/vde_sock_start_user.sh ]; then - echo "VDE SOCK START FILE NOT FOUND. NO VDE SETUP. EXITING" - exit 1 -else - echo "VDE SOCK START SCRIPT STARTED." - ./test/vde_sock_start_user.sh -fi - -rm -f /tmp/pico-mem-report-* -sleep 2 -ulimit -c unlimited -killall -wq picoapp.elf -killall -wq picoapp6.elf - - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ 6LoWPAN PING 1HOP (1500B) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(build/test/picoapp6.elf -6 0,0,0) & -pids="$! " -sleep 1 -(build/test/picoapp6.elf -6 1,2,1 -a noop) & -pids+="$! " -sleep 1 -build/test/picoapp6.elf -6 2,1,0 -a ping,2aaa:abcd:0000:0000:0200:00aa:ab00:0001,1500,0,1 || exit 1 -#TODO roll out this check for all "daemon" processes -for pid in $pids; do ps -o pid= -p $pid || exit 1; done # check whether daemon processes didn't die from e.g. ASAN -killall -w picoapp6.elf -s SIGQUIT - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ 6LoWPAN UDP 1HOP (1400B) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -#TODO are these "daemon" processes that need to be killed, or are they intended to halt on their own, giving a status code? -(build/test/picoapp6.elf -6 0,0,0) & -sleep 1 -(build/test/picoapp6.elf -6 1,2,1 -a udpecho,::0,6667,) & -sleep 1 -build/test/picoapp6.elf -6 2,1,0 -a udpclient,2aaa:abcd:0000:0000:0200:00aa:ab00:0001,6667,6667,1400,10,1, || exit 1 -killall -w picoapp6.elf -s SIGQUIT - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ MULTICAST6 TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic1,/tmp/pic0.ctl,aaaa::2,ffff::, -a mcastreceive_ipv6,aaaa::2,ff00::e007:707,6667,6667,) & -(./build/test/picoapp6.elf --vde pic2,/tmp/pic0.ctl,aaaa::3,ffff::, -a mcastreceive_ipv6,aaaa::3,ff00::e007:707,6667,6667,) & -(./build/test/picoapp6.elf --vde pic3,/tmp/pic0.ctl,aaaa::4,ffff::, -a mcastreceive_ipv6,aaaa::4,ff00::e007:707,6667,6667,) & -sleep 2 - ./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::, -a mcastsend_ipv6,aaaa::1,ff00::e007:707,6667,6667,|| exit 1 -killall -w picoapp6.elf -s SIGQUIT - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ PING6 LOCALHOST TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -./build/test/picoapp6.elf --loop -a ping,::1,,,, || exit 1 -killall -w picoapp6.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ PING6 TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::,,,,) & -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::2,ffff::,,, -a ping,aaaa::1,,,, || exit 1 -killall -w picoapp6.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ PING6 TEST (aborted in 4 seconds...) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::,,,,) & -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::2,ffff::,,, -a ping,aaaa::1,64,4,,) & -sleep 7 -killall -w picoapp6.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP6 TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::,,, -a tcpbench,r,6667,,) & -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::2,ffff::,,, -a tcpbench,t,aaaa::1,6667,, || exit 1 -killall -w picoapp6.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP6 TEST (with 2% packet loss on both directions) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::,,2,2, -a tcpbench,r,6667,,) & -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::2,ffff::,,, -a tcpbench,t,aaaa::1,6667,, || exit 1 -killall -w picoapp6.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP6 TEST (nagle) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::,,, -a tcpbench,r,6667,n,) & -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::2,ffff::,,, -a tcpbench,t,aaaa::1,6667,n, || exit 1 -killall -w picoapp6.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ UDP6 TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::1,ffff::,,, -a udpecho,::0,6667,) & -pids="$! " -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,aaaa::2,ffff::,,, -a udpclient,aaaa::1,6667,6667,1400,100,10, || exit 1 -wait $pids || exit 1 -killall -w picoapp6.elf - -echo -echo -echo -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ IPV6 FWD TCP TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic1.ctl,2001:aabb::2,ffff:ffff::,2001:aabb::ff,, -a tcpbench,r,6667,,) & -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,2001:aaaa::ff,ffff:ffff::,,, --vde pic1,/tmp/pic1.ctl,2001:aabb::ff,ffff:ffff::,,, -a noop,) & -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,2001:aaaa::1,ffff:ffff::,2001:aaaa::ff,, -a tcpbench,t,2001:aabb::2,6667,, || exit 1 -sleep 2 -killall -w picoapp6.elf - - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ MULTICAST TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic2:/tmp/pic0.ctl:10.40.0.4:255.255.0.0: -a mcastreceive:10.40.0.4:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic3:/tmp/pic0.ctl:10.40.0.5:255.255.0.0: -a mcastreceive:10.40.0.5:224.7.7.7:6667:6667:) & -sleep 2 -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667: || exit 1 -killall -w picoapp.elf - -echo -echo -echo -echo -echo - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ IPV4 tests! ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ PING LOCALHOST TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -./build/test/picoapp.elf --loop -a ping:127.0.0.1:::: || exit 1 - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ PING TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0:::) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a ping:10.40.0.8:::: || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ PING TEST -- Aborted in 4 seconds ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0:::) & -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a ping:10.40.0.8:64:4::) & -sleep 7 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0:::: -a tcpbench:r:6667::) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a tcpbench:t:10.40.0.8:6667:: || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP TEST (with global route) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0:::: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.0.0:10.50.0.1: -a tcpbench:r:6667::) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a tcpbench:t:10.40.0.8:6667:: || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP TEST (with 2% packet loss on both directions) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::2:2: -a tcpbench:r:6667::) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a tcpbench:t:10.40.0.8:6667:: || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TCP TEST (nagle) ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a tcpbench:r:6667:n:) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a tcpbench:t:10.40.0.8:6667:n: || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ UDP TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a udpecho:10.40.0.8:6667:) & -pids="$! " -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a udpclient:10.40.0.8:6667:6667:1400:100:10: || exit 1 -wait $pids || exit 1 - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ UDP TEST with fragmentation ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a udpecho:10.40.0.8:6667:) & -pids="$! " -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a udpclient:10.40.0.8:6667:6667:4500:100:10: || exit 1 -wait $pids || exit 1 - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ NAT TCP TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.10:255.255.0.0::: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.0.0: -a natbox:10.50.0.10) & -sleep 2 -(./build/test/picoapp.elf --vde pic0:/tmp/pic1.ctl:10.50.0.8:255.255.0.0::: -a tcpbench:r:6667:) & -sleep 2 -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10::: -a tcpbench:t:10.50.0.8:6667: || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ NAT UDP TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.10:255.255.0.0::: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.0.0::: -a natbox:10.50.0.10) & -(./build/test/picoapp.elf --vde pic0:/tmp/pic1.ctl:10.50.0.8:255.255.0.0::: -a udpecho:10.50.0.8:6667:) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10::: -a udpclient:10.50.0.8:6667:6667:1400:100:10: || exit 1 -#sometimes udpecho finishes before reaching wait %2 -#wait %2 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ MULTICAST TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0::: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic2:/tmp/pic0.ctl:10.40.0.4:255.255.0.0::: -a mcastreceive:10.40.0.4:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic3:/tmp/pic0.ctl:10.40.0.5:255.255.0.0::: -a mcastreceive:10.40.0.5:224.7.7.7:6667:6667:) & -sleep 2 -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0::: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667: || exit 1 -killall -w picoapp.elf - -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ DHCP TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.1:255.255.0.0::: -a dhcpserver:pic0:10.40.0.1:255.255.255.0:64:128:) & -./build/test/picoapp.elf --barevde pic0:/tmp/pic0.ctl: -a dhcpclient:pic0 || exit 1 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ DHCP DUAL TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0::: -a dhcpserver:pic0:10.40.0.2:255.255.255.0:64:128:) & -(./build/test/picoapp.elf --vde pic1:/tmp/pic1.ctl:10.50.0.2:255.255.0.0::: -a dhcpserver:pic1:10.50.0.2:255.255.255.0:64:128:) & -./build/test/picoapp.elf --barevde pic0:/tmp/pic0.ctl: --barevde pic1:/tmp/pic1.ctl: -a dhcpclient:pic0:pic1: || exit 1 -killall -w picoapp.elf - -#TO DO: the ping address 169.254.22.5 is hardcoded in the slaacv4 test. Nice to pass that by parameter -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ SLAACV4 TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:169.254.22.5:255.255.0.0:::) & -./build/test/picoapp.elf --barevde pic0:/tmp/pic0.ctl: -a slaacv4:pic0 || exit 1 -killall -w picoapp.elf - - -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0:10.40.0.1::: -a udpdnsclient:www.google.be:173.194.67.94:: & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0:10.40.0.1::: -a udpdnsclient:ipv6.google.be:doesntmatter:ipv6: & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.0.0:10.50.0.1::: -a sntp:0.europe.pool.ntp.org & -sleep 20 -killall -w picoapp.elf - - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ MDNS TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -#retrieve a local mdns host name from the host -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app mdns:hostfoo.local:hostbar.local:) & -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app mdns:hostbar.local:hostfoo.local:) & -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app mdns:hostfoobar.local:nonexisting.local:) & -sleep 10 -killall -w picoapp.elf - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ DNS_SD TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -#register a service -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app dns_sd:host.local:WebServer) & -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app dns_sd:host.local:WebServer) & -sleep 30 -killall -w picoapp.elf - -sleep 1 -sync - - -# TFTP TEST BEGINS... - -if [ ! -d $TFTP_WORK_DIR ]; then - mkdir $TFTP_WORK_DIR || exit 1 -fi -if [ ! -d ${TFTP_WORK_SUBDIR}/server ]; then - mkdir $TFTP_WORK_SUBDIR || exit 1 -fi - -pushd $TFTP_WORK_DIR - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TFTP GET TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -tftp_setup $TFTP_WORK_DIR -(${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app tftp:S:) & -cd $TFTP_WORK_SUBDIR -sleep 2 -${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app tftp:R:${TFTP_WORK_FILE}:10.50.0.2: || tftp_cleanup 1 -sleep 3 -killall -w picoapp.elf - -sleep 1 - -rm $TFTP_WORK_FILE - -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -echo "~~~ TFTP PUT TEST ~~~" -echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -(${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app tftp:S:) & -cd $TFTP_WORK_DIR -tftp_setup $TFTP_WORK_DIR -sleep 2 -${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app tftp:T:${TFTP_WORK_FILE}:10.50.0.2: || tftp_cleanup 1 -sleep 3 - -tftp_cleanup -popd -# TFTP TEST ENDS. - -MAXMEM=`cat /tmp/pico-mem-report-* | sort -r -n |head -1` -echo -echo -echo -echo "MAX memory used: $MAXMEM" -rm -f /tmp/pico-mem-report-* - -./test/vde_sock_start_user.sh stop -echo "SUCCESS!" diff --git a/ext/picotcp/test/coverage.sh b/ext/picotcp/test/coverage.sh deleted file mode 100755 index f326bc7..0000000 --- a/ext/picotcp/test/coverage.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -./test/units.sh || exit 1 -./test/autotest.sh || exit 2 -exit 0 diff --git a/ext/picotcp/test/dummy.c b/ext/picotcp/test/dummy.c deleted file mode 100644 index 7420581..0000000 --- a/ext/picotcp/test/dummy.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "pico_stack.h" - -#if defined(PICO_SUPPORT_RTOS) || defined (PICO_SUPPORT_PTHREAD) -volatile uint32_t pico_ms_tick; -#endif - -int main(void) -{ - pico_stack_init(); - pico_stack_tick(); - return 0; -} diff --git a/ext/picotcp/test/examples/Makefile b/ext/picotcp/test/examples/Makefile deleted file mode 100644 index 3434891..0000000 --- a/ext/picotcp/test/examples/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -PREFIX?=../../build -CFLAGS+=-I../../include/ -I../../modules -I../../build/include -I . -ggdb - - -$(PREFIX)/examples/%.o: %.c - @mkdir -p $(PREFIX)/examples - @echo -e "\t[CC] $@" - @$(CC) -c $(CFLAGS) -o $@ $< - -OBJS:= \ -$(PREFIX)/examples/dhcp_client.o \ -$(PREFIX)/examples/dhcp_server.o \ -$(PREFIX)/examples/dns_sd.o \ -$(PREFIX)/examples/dnsclient.o \ -$(PREFIX)/examples/mdns.o \ -$(PREFIX)/examples/multicast_recv.o \ -$(PREFIX)/examples/multicast_ip6_recv.o \ -$(PREFIX)/examples/multicast_send.o \ -$(PREFIX)/examples/multicast_ip6_send.o \ -$(PREFIX)/examples/natbox.o \ -$(PREFIX)/examples/noop.o \ -$(PREFIX)/examples/ping.o \ -$(PREFIX)/examples/slaacv4.o \ -$(PREFIX)/examples/sntp.o \ -$(PREFIX)/examples/tcpbench.o \ -$(PREFIX)/examples/tcpclient.o \ -$(PREFIX)/examples/tcpecho.o \ -$(PREFIX)/examples/tftp.o \ -$(PREFIX)/examples/udp_client.o \ -$(PREFIX)/examples/udp_echo.o \ -$(PREFIX)/examples/udpnat.o \ -$(PREFIX)/examples/udp_sendto_test.o \ -$(PREFIX)/examples/iperfc.o \ - - -all: $(OBJS) diff --git a/ext/picotcp/test/examples/dhcp_client.c b/ext/picotcp/test/examples/dhcp_client.c deleted file mode 100644 index bb0ee20..0000000 --- a/ext/picotcp/test/examples/dhcp_client.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "utils.h" -#include -#include -#include -#include -#include -/*** START DHCP Client ***/ -#ifdef PICO_SUPPORT_DHCPC - -/* This must stay global, its lifetime is the same as the dhcp negotiation */ -uint32_t dhcpclient_xid; - - -static uint8_t dhcpclient_devices = 0; - -void ping_callback_dhcpclient(struct pico_icmp4_stats *s) -{ - char host[30] = { }; - - pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("DHCP client: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", - s->size, host, s->seq, (long unsigned int)s->time); - if (s->seq >= 3) { - dbg("DHCP client: TEST SUCCESS!\n"); - if (--dhcpclient_devices <= 0) - exit(0); - } - } else { - dbg("DHCP client: ping %lu to %s error %d\n", s->seq, host, s->err); - dbg("DHCP client: TEST FAILED!\n"); - exit(1); - } -} - -void callback_dhcpclient(void *arg, int code) -{ - struct pico_ip4 address = ZERO_IP4, gateway = ZERO_IP4; - char s_address[16] = { }, s_gateway[16] = { }; - - printf("DHCP client: callback happened with code %d!\n", code); - if (code == PICO_DHCP_SUCCESS) { - address = pico_dhcp_get_address(arg); - gateway = pico_dhcp_get_gateway(arg); - pico_ipv4_to_string(s_address, address.addr); - pico_ipv4_to_string(s_gateway, gateway.addr); - printf("DHCP client: got IP %s assigned with cli %p\n", s_address, arg); -#ifdef PICO_SUPPORT_PING - pico_icmp4_ping(s_gateway, 3, 1000, 5000, 32, ping_callback_dhcpclient); - /* optional test to check routing when links get added and deleted */ - /* do { - char *new_arg = NULL, *p = NULL; - new_arg = calloc(1, strlen(s_address) + strlen(":224.7.7.7:6667:6667") + 1); - p = strcat(new_arg, s_address); - p = strcat(p + strlen(s_address), ":224.7.7.7:6667:6667"); - app_mcastsend(new_arg); - } while (0); - */ -#endif - } -} - -void app_dhcp_client(char *arg) -{ - char *sdev = NULL; - char *nxt = arg; - struct pico_device *dev = NULL; - - if (!nxt) - goto out; - - while (nxt) { - if (nxt) { - nxt = cpy_arg(&sdev, nxt); - if(!sdev) { - goto out; - } - } - - dev = pico_get_device(sdev); - if(dev == NULL) { - if (sdev) - free(sdev); - - printf("%s: error getting device %s: %s\n", __FUNCTION__, dev->name, strerror(pico_err)); - exit(255); - } - - printf("Starting negotiation\n"); - - if (pico_dhcp_initiate_negotiation(dev, &callback_dhcpclient, &dhcpclient_xid) < 0) { - printf("%s: error initiating negotiation: %s\n", __FUNCTION__, strerror(pico_err)); - if (sdev) - free(sdev); - - exit(255); - } - - if (sdev) - free(sdev); - - dhcpclient_devices++; - } - return; - -out: - fprintf(stderr, "dhcpclient expects the following format: dhcpclient:dev_name:[dev_name]\n"); - if (sdev) - free(sdev); - - exit(255); -} -#endif -/*** END DHCP Client ***/ diff --git a/ext/picotcp/test/examples/dhcp_server.c b/ext/picotcp/test/examples/dhcp_server.c deleted file mode 100644 index 63ff8fe..0000000 --- a/ext/picotcp/test/examples/dhcp_server.c +++ /dev/null @@ -1,99 +0,0 @@ -#include "utils.h" -#include -#include -#include - -/*** START DHCP Server ***/ -#ifdef PICO_SUPPORT_DHCPD -/* ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.1:255.255.0.0: -a dhcpserver:pic0:10.40.0.1:255.255.255.0:64:128 - * ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.10:255.255.255.0: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.255.0: \ - * -a dhcpserver:pic0:10.40.0.10:255.255.255.0:64:128:pic1:10.50.0.10:255.255.255.0:64:128 - */ -void app_dhcp_server(char *arg) -{ - struct pico_device *dev = NULL; - struct pico_dhcp_server_setting s = { - 0 - }; - int pool_start = 0, pool_end = 0; - char *s_name = NULL, *s_addr = NULL, *s_netm = NULL, *s_pool_start = NULL, *s_pool_end = NULL; - char *nxt = arg; - - if (!nxt) - goto out; - - while (nxt) { - if (nxt) { - nxt = cpy_arg(&s_name, nxt); - if (!s_name) { - goto out; - } - } else { - goto out; - } - - if (nxt) { - nxt = cpy_arg(&s_addr, nxt); - if (s_addr) { - pico_string_to_ipv4(s_addr, &s.server_ip.addr); - } else { - goto out; - } - } else { - goto out; - } - - if (nxt) { - nxt = cpy_arg(&s_netm, nxt); - if (s_netm) { - pico_string_to_ipv4(s_netm, &s.netmask.addr); - } else { - goto out; - } - } else { - goto out; - } - - if (nxt) { - nxt = cpy_arg(&s_pool_start, nxt); - if (s_pool_start && atoi(s_pool_start)) { - pool_start = atoi(s_pool_start); - } else { - goto out; - } - } else { - goto out; - } - - if (nxt) { - nxt = cpy_arg(&s_pool_end, nxt); - if (s_pool_end && atoi(s_pool_end)) { - pool_end = atoi(s_pool_end); - } else { - goto out; - } - } else { - goto out; - } - - dev = (struct pico_device *)pico_get_device(s_name); - if (dev == NULL) { - fprintf(stderr, "No device with name %s found\n", s_name); - exit(255); - } - - s.dev = dev; - s.pool_start = (s.server_ip.addr & s.netmask.addr) | long_be(pool_start); - s.pool_end = (s.server_ip.addr & s.netmask.addr) | long_be(pool_end); - - pico_dhcp_server_initiate(&s); - } - return; - -out: - fprintf(stderr, "dhcpserver expects the following format: dhcpserver:dev_name:dev_addr:dev_netm:pool_start:pool_end\n"); - exit(255); - -} -#endif -/*** END DHCP Server ***/ diff --git a/ext/picotcp/test/examples/dns_sd.c b/ext/picotcp/test/examples/dns_sd.c deleted file mode 100644 index dd2e96f..0000000 --- a/ext/picotcp/test/examples/dns_sd.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "utils.h" -#include -#include -#include -#include -#include - -/*** START DNS_SD ***/ -#ifdef PICO_SUPPORT_DNS_SD - -#define TTL 30 -#define SECONDS 10 - -static int fully_initialized = 0; -static char *service_name = NULL; - -void dns_sd_claimed_callback( pico_mdns_rtree *tree, - char *str, - void *arg ) -{ - printf("DONE - Registering DNS-SD Service\n"); - - IGNORE_PARAMETER(tree); - IGNORE_PARAMETER(str); - IGNORE_PARAMETER(arg); -} - -void dns_sd_init_callback( pico_mdns_rtree *tree, - char *str, - void *arg ) -{ - PICO_DNS_SD_KV_VECTOR_DECLARE(key_value_pair_vector); - - IGNORE_PARAMETER(str); - IGNORE_PARAMETER(arg); - IGNORE_PARAMETER(tree); - - pico_dns_sd_kv_vector_add(&key_value_pair_vector, "key", "value"); - - printf("DONE - Initialising DNS Service Discovery module.\n"); - - if (pico_dns_sd_register_service(service_name, - "_http._tcp", 80, - &key_value_pair_vector, - TTL, dns_sd_claimed_callback, NULL) < 0) { - printf("Registering service failed!\n"); - } - - fully_initialized = 1; -} - -void app_dns_sd(char *arg, struct pico_ip4 address) -{ - char *hostname; - char *nxt = arg; - uint64_t starttime = 0; - int once = 0; - - if (!nxt) { - exit(255); - } - - nxt = cpy_arg(&hostname, nxt); - if(!hostname) { - exit(255); - } - - if(!nxt) { - printf("Not enough args supplied!\n"); - exit(255); - } - - nxt = cpy_arg(&service_name, nxt); - if(!service_name) { - exit(255); - } - - printf("\nStarting DNS Service Discovery module...\n"); - if (pico_dns_sd_init(hostname, address, &dns_sd_init_callback, NULL) != 0) { - printf("Initialisation returned with Error!\n"); - exit(255); - } - - printf("\nTry reinitialising DNS-SD\n"); - if (pico_dns_sd_init(hostname, address, &dns_sd_init_callback, NULL)) { - printf("Initialisation returned with Error!\n"); - exit(255); - } - - printf("DONE - Re-initialising DNS-SD module.\n"); - - starttime = PICO_TIME_MS(); - printf("Starting time: %d\n", starttime); - - while(1) { - pico_stack_tick(); - usleep(2000); - - if (((PICO_TIME_MS() - starttime) > SECONDS * 1000) && fully_initialized && !once) { - printf("\nTry reinitialising DNS-SD (a second time)\n"); - if (pico_dns_sd_init(hostname, address, &dns_sd_init_callback, NULL)) { - printf("Initialisation returned with Error!\n"); - exit(255); - } - once = 1; - printf("DONE - Re-initialising mDNS module. (a second time)\n"); - } - } -} - -#endif -/*** END DNS_SD ***/ diff --git a/ext/picotcp/test/examples/dnsclient.c b/ext/picotcp/test/examples/dnsclient.c deleted file mode 100644 index 0a1d276..0000000 --- a/ext/picotcp/test/examples/dnsclient.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include -#include "utils.h" -extern int IPV6_MODE; - -/*** START UDP DNS CLIENT ***/ -/* - ./test/vde_sock_start.sh - echo 1 > /proc/sys/net/ipv4/ip_forward - iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE - iptables -A FORWARD -i pic0 -o wlan0 -j ACCEPT - iptables -A FORWARD -i wlan0 -o pic0 -j ACCEPT - ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0:10.40.0.1: -a udpdnsclient:www.google.be:173.194.67.94 - */ -void cb_udpdnsclient_getaddr(char *ip, void *arg) -{ - uint8_t *id = (uint8_t *) arg; - - if (!ip) { - picoapp_dbg("%s: ERROR occured! (id: %u)\n", __FUNCTION__, *id); - return; - } - - picoapp_dbg("%s: ip %s (id: %u)\n", __FUNCTION__, ip, *id); - if (arg) - PICO_FREE(arg); -} - -void cb_udpdnsclient_getname(char *name, void *arg) -{ - uint8_t *id = (uint8_t *) arg; - - if (!name) { - picoapp_dbg("%s: ERROR occured! (id: %u)\n", __FUNCTION__, *id); - return; - } - - picoapp_dbg("%s: name %s (id: %u)\n", __FUNCTION__, name, *id); - if (arg) - PICO_FREE(arg); -} - -void app_udpdnsclient(char *arg) -{ - struct pico_ip4 nameserver; - char *dname, *daddr; - char *nxt; - char *ipver; - int v = 4; - uint8_t *getaddr_id, *getname_id, *getaddr6_id, *getname6_id; - - nxt = cpy_arg(&dname, arg); - if (!dname || !nxt) { - picoapp_dbg(" udpdnsclient expects the following format: udpdnsclient:dest_name:dest_ip:[ipv6]\n"); - exit(255); - } - - nxt = cpy_arg(&daddr, nxt); - if (!daddr || !nxt) { - picoapp_dbg(" udpdnsclient expects the following format: udpdnsclient:dest_name:dest_ip:[ipv6]\n"); - exit(255); - } - - nxt = cpy_arg(&ipver, nxt); - if (!ipver || strcmp("ipv6", ipver) != 0) - v = 4; - else - v = 6; - - picoapp_dbg("UDP DNS client started.\n"); - - picoapp_dbg("----- Deleting non existant nameserver -----\n"); - pico_string_to_ipv4("127.0.0.1", &nameserver.addr); - pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_DEL); - picoapp_dbg("----- Adding 8.8.8.8 nameserver -----\n"); - pico_string_to_ipv4("8.8.8.8", &nameserver.addr); - pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_ADD); - picoapp_dbg("----- Deleting 8.8.8.8 nameserver -----\n"); - pico_string_to_ipv4("8.8.8.8", &nameserver.addr); - pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_DEL); - picoapp_dbg("----- Adding 8.8.8.8 nameserver -----\n"); - pico_string_to_ipv4("8.8.8.8", &nameserver.addr); - pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_ADD); - picoapp_dbg("----- Adding 8.8.4.4 nameserver -----\n"); - pico_string_to_ipv4("8.8.4.4", &nameserver.addr); - pico_dns_client_nameserver(&nameserver, PICO_DNS_NS_ADD); - if (!IPV6_MODE) { - if (v == 4) { - picoapp_dbg("Mode: IPv4\n"); - getaddr_id = calloc(1, sizeof(uint8_t)); - *getaddr_id = 1; - picoapp_dbg(">>>>> DNS GET ADDR OF %s\n", dname); - pico_dns_client_getaddr(dname, &cb_udpdnsclient_getaddr, getaddr_id); - - getname_id = calloc(1, sizeof(uint8_t)); - *getname_id = 2; - picoapp_dbg(">>>>> DNS GET NAME OF %s\n", daddr); - pico_dns_client_getname(daddr, &cb_udpdnsclient_getname, getname_id); - return; - } - - picoapp_dbg("Mode: IPv6\n"); - -#ifdef PICO_SUPPORT_IPV6 - getaddr6_id = calloc(1, sizeof(uint8_t)); - *getaddr6_id = 3; - picoapp_dbg(">>>>> DNS GET ADDR6 OF %s\n", dname); - pico_dns_client_getaddr6(dname, &cb_udpdnsclient_getaddr, getaddr6_id); - getname6_id = calloc(1, sizeof(uint8_t)); - *getname6_id = 4; - picoapp_dbg(">>>>> DNS GET NAME OF ipv6 addr 2a00:1450:400c:c06::64\n"); - pico_dns_client_getname6("2a00:1450:400c:c06::64", &cb_udpdnsclient_getname, getname6_id); -#endif - } - - return; -} -/*** END UDP DNS CLIENT ***/ diff --git a/ext/picotcp/test/examples/iperfc.c b/ext/picotcp/test/examples/iperfc.c deleted file mode 100644 index fbe7e67..0000000 --- a/ext/picotcp/test/examples/iperfc.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include "pico_ipv6.h" -#include "pico_stack.h" -#include "pico_socket.h" -#include "utils.h" - -#define DURATION 30 - -struct iperf_hdr { - int32_t flags; /* 0 */ - int32_t numThreads; /* 1 */ - int32_t mPort; /* 5001 */ - int32_t bufferlen; /* 0 */ - int32_t mWinBand; /* 0 */ - int32_t mAmount; /* 0xfffffc18 */ -}; - -#define IPERF_PORT 5001 -#define MTU 1444 -#define SEND_BUF_SIZ (1024 * 2048) - -char *cpy_arg(char **dst, char *str); -extern int IPV6_MODE; - -static pico_time deadline; - -static void panic(void) -{ - for(;; ) ; -} - -static char buf[MTU] = {}; - -static void buf_paint(void) -{ - char paint[11] = "0123456789"; - int i; - for (i = 0; i < MTU; i++) { - buf[i] = paint[i % 10]; - } -} - -static void send_hdr(struct pico_socket *s) -{ - struct iperf_hdr hdr = {}; - hdr.numThreads = long_be(1); - hdr.mPort = long_be(5001); - hdr.mAmount = long_be(0xfffffc18); - pico_socket_write(s, &hdr, sizeof(hdr)); - deadline = PICO_TIME_MS() + DURATION * 1000; -} - -static void iperf_cb(uint16_t ev, struct pico_socket *s) -{ - int r; - static int end = 0; - if (ev & PICO_SOCK_EV_CONN) { - send_hdr(s); - return; - } - - if ((!end) && (ev & PICO_SOCK_EV_WR)) { - if (PICO_TIME_MS() > deadline) { - pico_socket_close(s); - if (!pico_timer_add(2000, deferred_exit, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - end++; - } - - pico_socket_write(s, buf, MTU); - } - - if (!(end) && (ev & (PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE))) { - if (!pico_timer_add(2000, deferred_exit, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - end++; - } -} - -static void iperfc_socket_setup(union pico_address *addr, uint16_t family) -{ - int yes = 1; - uint16_t send_port = 0; - struct pico_socket *s = NULL; - uint32_t bufsize = SEND_BUF_SIZ; - send_port = short_be(5001); - s = pico_socket_open(family, PICO_PROTO_TCP, &iperf_cb); - pico_socket_setoption(s, PICO_SOCKET_OPT_SNDBUF, &bufsize); - pico_socket_connect(s, addr, send_port); -} - -void app_iperfc(char *arg) -{ - struct pico_ip4 my_eth_addr, netmask; - struct pico_device *pico_dev_eth; - char *daddr = NULL, *dport = NULL; - char *nxt = arg; - uint16_t send_port = 0, listen_port = short_be(5001); - int i = 0, ret = 0, yes = 1; - struct pico_socket *s = NULL; - uint16_t family = PICO_PROTO_IPV4; - union pico_address dst = { - .ip4 = {0}, .ip6 = {{0}} - }; - union pico_address inaddr_any = { - .ip4 = {0}, .ip6 = {{0}} - }; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&daddr, arg); - if (daddr) { - if (!IPV6_MODE) - pico_string_to_ipv4(daddr, &dst.ip4.addr); - - #ifdef PICO_SUPPORT_IPV6 - else { - pico_string_to_ipv6(daddr, dst.ip6.addr); - family = PICO_PROTO_IPV6; - } - #endif - } else { - goto out; - } - } else { - /* missing dest_addr */ - goto out; - } - - iperfc_socket_setup(&dst, family); - return; -out: - dbg("Error parsing options!\n"); - exit(1); -} - diff --git a/ext/picotcp/test/examples/mdns.c b/ext/picotcp/test/examples/mdns.c deleted file mode 100644 index 853448f..0000000 --- a/ext/picotcp/test/examples/mdns.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "utils.h" -#include "pico_dns_common.h" -#include "pico_mdns.h" -#include "pico_ipv4.h" -#include "pico_addressing.h" - -/*** START MDNS ***/ - -#ifdef PICO_SUPPORT_MDNS - -#define SECONDS 10 - -static int fully_initialized = 0; - -void mdns_init_callback( pico_mdns_rtree *rtree, - char *str, - void *arg ) -{ - printf("\nInitialised with hostname: %s\n\n", str); - - fully_initialized = 1; -} - -void app_mdns(char *arg, struct pico_ip4 address) -{ - char *hostname, *peername; - char *nxt = arg; - uint64_t starttime = 0; - int once = 0; - - if (!nxt) - exit(255); - - nxt = cpy_arg(&hostname, nxt); - if(!hostname) { - exit(255); - } - - if(!nxt) { - printf("Not enough args supplied!\n"); - exit(255); - } - - nxt = cpy_arg(&peername, nxt); - if(!peername) { - exit(255); - } - - printf("\nStarting mDNS module...\n"); - if (pico_mdns_init(hostname, address, &mdns_init_callback, NULL)) { - printf("Initialisation returned with Error!\n"); - exit(255); - } - - printf("\nTry reinitialising mDNS\n"); - if (pico_mdns_init(hostname, address, &mdns_init_callback, NULL)) { - printf("Initialisation returned with Error!\n"); - exit(255); - } - - printf("DONE - Re-initialising mDNS module.\n"); - - starttime = PICO_TIME_MS(); - printf("Starting time: %d\n", starttime); - - while(1) { - pico_stack_tick(); - usleep(2000); - - if (((PICO_TIME_MS() - starttime) > SECONDS * 1000) && fully_initialized && !once) { - printf("\nTry reinitialising mDNS (a second time)\n"); - if (pico_mdns_init(hostname, address, &mdns_init_callback, NULL)) { - printf("Initialisation returned with Error!\n"); - exit(255); - } - once = 1; - printf("DONE - Re-initialising mDNS module. (a second time)\n"); - } - - } -} -#endif -/*** END MDNS ***/ diff --git a/ext/picotcp/test/examples/multicast_ip6_recv.c b/ext/picotcp/test/examples/multicast_ip6_recv.c deleted file mode 100644 index 22055fc..0000000 --- a/ext/picotcp/test/examples/multicast_ip6_recv.c +++ /dev/null @@ -1,182 +0,0 @@ -#include "utils.h" -#include -#include - -extern void app_udpecho(char *arg); - -/*** START Multicast RECEIVE + ECHO ***/ -/* - * multicast receive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port:sendto_port - * link_addr: mcastreceive picoapp IP address - * mcast_addr: multicast IP address to receive - * listen_port: port number on which the mcastreceive listens - * sendto_port: port number to echo multicast traffic to (echo to originating IP address) - * - * f.e.: ./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667 - */ -extern struct udpclient_pas *udpclient_pas; -extern struct udpecho_pas *udpecho_pas; -#ifdef PICO_SUPPORT_MCAST -void app_mcastreceive_ipv6(char *arg) -{ - char *new_arg = NULL, *p = NULL, *nxt = arg; - char *laddr = NULL, *maddr = NULL, *lport = NULL, *sport = NULL; - uint16_t listen_port = 0; - union pico_address inaddr_link = { - 0 - }, inaddr_mcast = { - 0 - }, src[5] = { - {.ip6 = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xac, 0x10, 0x01, 0 }}, - {.ip6 = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xac, 0x10, 0x01, 0x10}}, - {.ip6 = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xac, 0x10, 0x01, 0x01 }}, - {.ip6 = { 0xff, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0xe0, 0x01, 0x01, 0x01 }}, - }; - struct pico_ip_mreq mreq = ZERO_MREQ_IP6; - struct pico_ip_mreq_source mreq_source = ZERO_MREQ_SRC_IP6; - /* start of parameter parsing */ - if (nxt) { - nxt = cpy_arg(&laddr, nxt); - if (laddr) { - pico_string_to_ipv6(laddr, &inaddr_link.ip6.addr[0]); - } else { - goto out; - } - } else { - /* no arguments */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&maddr, nxt); - if (maddr) { - pico_string_to_ipv6(maddr, &inaddr_mcast.ip6.addr[0]); - } else { - goto out; - } - } else { - /* missing multicast address */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - listen_port = short_be(atoi(lport)); - } else { - /* incorrect listen_port */ - goto out; - } - } else { - /* missing listen_port */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&sport, nxt); - if (sport && atoi(sport)) { - /* unused at this moment */ - /* send_port = short_be(atoi(sport)); */ - } else { - /* incorrect send_port */ - goto out; - } - } else { - /* missing send_port */ - goto out; - } - - /* end of parameter parsing */ - - printf("\n%s: multicast receive started. Receiving packets on [%s]:%d\n\n", __FUNCTION__, maddr, short_be(listen_port)); - - /* udpecho:bind_addr:listen_port[:sendto_port:datasize] */ - new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(",64:") + 1); - p = strcat(new_arg, laddr); - p = strcat(p + strlen(laddr), ","); - p = strcat(p + 1, lport); - p = strcat(p + strlen(lport), ","); - p = strcat(p + 1, sport); - p = strcat(p + strlen(sport), ",64,"); - - /* DAD needs to verify the link address before we can continue */ - while(!pico_ipv6_link_get(&inaddr_link.ip6)) { - pico_stack_tick(); - usleep(2000); - } - app_udpecho(new_arg); - - memcpy(&mreq.mcast_group_addr, &inaddr_mcast, sizeof(struct pico_ip6)); - memcpy( &mreq_source.mcast_group_addr, &inaddr_mcast, sizeof(struct pico_ip6)); - memcpy(&mreq.mcast_link_addr, &inaddr_link, sizeof(struct pico_ip6)); - memcpy(&mreq_source.mcast_link_addr, &inaddr_link, sizeof(struct pico_ip6)); - memcpy(&mreq_source.mcast_source_addr, &src[0], sizeof(struct pico_ip6)); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_BLOCK_SOURCE, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_BLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_UNBLOCK_SOURCE, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_UNBLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - memcpy(&mreq_source.mcast_source_addr, &src[1], sizeof(struct pico_ip6)); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - memcpy(&mreq_source.mcast_source_addr, &src[2], sizeof(struct pico_ip6)); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - memcpy(&mreq_source.mcast_group_addr, &src[3], sizeof(struct pico_ip6)); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - return; - -out: - fprintf(stderr, "mcastreceive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port[:send_port]\n"); - exit(255); -} -#else -void app_mcastreceive_ipv6(char *arg) -{ - printf("ERROR: PICO_SUPPORT_MCAST disabled\n"); - return; -} -#endif -/*** END Multicast RECEIVE + ECHO ***/ diff --git a/ext/picotcp/test/examples/multicast_ip6_send.c b/ext/picotcp/test/examples/multicast_ip6_send.c deleted file mode 100644 index 1b2615b..0000000 --- a/ext/picotcp/test/examples/multicast_ip6_send.c +++ /dev/null @@ -1,140 +0,0 @@ -#include "utils.h" -#include -#include -#include - -extern void app_udpclient(char *arg); -/*** START Multicast SEND ***/ -/* - * multicast send expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port - * link_addr: mcastsend picoapp IP address - * mcast_addr: multicast IP address to send to - * sendto_port: port number to send multicast traffic to - * listen_port: port number on which the mcastsend can receive data - * - * f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667 - */ -extern struct udpclient_pas *udpclient_pas; -#ifdef PICO_SUPPORT_MCAST -void app_mcastsend_ipv6(char *arg) -{ - int retval = 0; - char *maddr = NULL, *laddr = NULL, *lport = NULL, *sport = NULL; - uint16_t sendto_port = 0; - struct pico_ip6 inaddr_link = { - 0 - }, inaddr_mcast = { - 0 - }; - char *new_arg = NULL, *p = NULL, *nxt = arg; - struct pico_ip_mreq mreq = ZERO_MREQ_IP6; - - /* start of parameter parsing */ - if (nxt) { - nxt = cpy_arg(&laddr, nxt); - if (laddr) { - pico_string_to_ipv6(laddr, &inaddr_link.addr[0]); - } else { - goto out; - } - } else { - /* no arguments */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&maddr, nxt); - if (maddr) { - pico_string_to_ipv6(maddr, &inaddr_mcast.addr[0]); - } else { - goto out; - } - } else { - /* missing multicast address */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&sport, nxt); - if (sport && atoi(sport)) { - sendto_port = short_be(atoi(sport)); - } else { - /* incorrect send_port */ - goto out; - } - } else { - /* missing send_port */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - /* unused at this moment */ - /* listen_port = short_be(atoi(lport)); */ - } else { - /* incorrect listen_port */ - goto out; - } - } else { - /* missing listen_port */ - goto out; - } - - picoapp_dbg("\n%s: mcastsend started. Sending packets to %s:%u\n\n", __FUNCTION__, maddr, short_be(sendto_port)); - - /* udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops] */ - new_arg = calloc(1, strlen(maddr) + 1 + strlen(sport) + 1 + strlen(lport) + strlen(",64,10,5,") + 1); - p = strcat(new_arg, maddr); - p = strcat(p + strlen(maddr), ","); - p = strcat(p + 1, sport); - p = strcat(p + strlen(sport), ","); - p = strcat(p + 1, lport); - p = strcat(p + strlen(lport), ",64,10,5,"); - - /* DAD needs to verify the link address before we can continue */ - while(!pico_ipv6_link_get(&inaddr_link)) { - pico_stack_tick(); - usleep(2000); - } - app_udpclient(new_arg); - - memcpy(&mreq.mcast_group_addr, &inaddr_mcast, sizeof(struct pico_ip6)); - memcpy(&mreq.mcast_link_addr, &inaddr_link, sizeof(struct pico_ip6)); - if(pico_socket_setoption(udpclient_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - picoapp_dbg("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - retval = 1; - } - - if (new_arg) - free(new_arg); - - if (lport) - free(lport); - - if (maddr) - free(maddr); - - if (sport) - free(sport); - - if (laddr) - free(laddr); - - if (retval) - exit(retval); - - return; - -out: - picoapp_dbg("mcastsend expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port\n"); - exit(255); -} -#else -void app_mcastsend_ipv6(char *arg) -{ - picoapp_dbg("ERROR: PICO_SUPPORT_MCAST disabled\n"); - return; -} -#endif -/*** END Multicast SEND ***/ diff --git a/ext/picotcp/test/examples/multicast_recv.c b/ext/picotcp/test/examples/multicast_recv.c deleted file mode 100644 index 8e95e26..0000000 --- a/ext/picotcp/test/examples/multicast_recv.c +++ /dev/null @@ -1,171 +0,0 @@ -#include "utils.h" -#include -#include - -extern void app_udpecho(char *arg); - -/*** START Multicast RECEIVE + ECHO ***/ -/* - * multicast receive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port:sendto_port - * link_addr: mcastreceive picoapp IP address - * mcast_addr: multicast IP address to receive - * listen_port: port number on which the mcastreceive listens - * sendto_port: port number to echo multicast traffic to (echo to originating IP address) - * - * f.e.: ./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667 - */ -extern struct udpclient_pas *udpclient_pas; -extern struct udpecho_pas *udpecho_pas; -#ifdef PICO_SUPPORT_MCAST -void app_mcastreceive(char *arg) -{ - char *new_arg = NULL, *p = NULL, *nxt = arg; - char *laddr = NULL, *maddr = NULL, *lport = NULL, *sport = NULL; - uint16_t listen_port = 0; - union pico_address inaddr_link = { - 0 - }, inaddr_mcast = { - 0 - }; - struct pico_ip_mreq mreq = ZERO_MREQ; - struct pico_ip_mreq_source mreq_source = ZERO_MREQ_SRC; - - /* start of parameter parsing */ - if (nxt) { - nxt = cpy_arg(&laddr, nxt); - if (laddr) { - pico_string_to_ipv4(laddr, &inaddr_link.ip4.addr); - } else { - goto out; - } - } else { - /* no arguments */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&maddr, nxt); - if (maddr) { - pico_string_to_ipv4(maddr, &inaddr_mcast.ip4.addr); - } else { - goto out; - } - } else { - /* missing multicast address */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - listen_port = short_be(atoi(lport)); - } else { - /* incorrect listen_port */ - goto out; - } - } else { - /* missing listen_port */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&sport, nxt); - if (sport && atoi(sport)) { - /* unused at this moment */ - /* send_port = short_be(atoi(sport)); */ - } else { - /* incorrect send_port */ - goto out; - } - } else { - /* missing send_port */ - goto out; - } - - /* end of parameter parsing */ - - printf("\n%s: multicast receive started. Receiving packets on %s:%d\n\n", __FUNCTION__, maddr, short_be(listen_port)); - - /* udpecho:bind_addr:listen_port[:sendto_port:datasize] */ - new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(":64:") + 1); - p = strcat(new_arg, laddr); - p = strcat(p + strlen(laddr), ":"); - p = strcat(p + 1, lport); - p = strcat(p + strlen(lport), ":"); - p = strcat(p + 1, sport); - p = strcat(p + strlen(sport), ":64:"); - - app_udpecho(new_arg); - - mreq.mcast_group_addr = mreq_source.mcast_group_addr = inaddr_mcast; - mreq.mcast_link_addr = mreq_source.mcast_link_addr = inaddr_link; - mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC100101); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_BLOCK_SOURCE, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_BLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_UNBLOCK_SOURCE, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_UNBLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC10010A); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) { - printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - } - - mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC100101); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - mreq_source.mcast_group_addr.ip4.addr = long_be(0XE0010101); - if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) { - printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err)); - } - - return; - -out: - fprintf(stderr, "mcastreceive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port[:send_port]\n"); - exit(255); -} -#else -void app_mcastreceive(char *arg) -{ - printf("ERROR: PICO_SUPPORT_MCAST disabled\n"); - return; -} -#endif -/*** END Multicast RECEIVE + ECHO ***/ diff --git a/ext/picotcp/test/examples/multicast_send.c b/ext/picotcp/test/examples/multicast_send.c deleted file mode 100644 index a0cd435..0000000 --- a/ext/picotcp/test/examples/multicast_send.c +++ /dev/null @@ -1,129 +0,0 @@ -#include "utils.h" -#include -#include - -extern void app_udpclient(char *arg); -/*** START Multicast SEND ***/ -/* - * multicast send expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port - * link_addr: mcastsend picoapp IP address - * mcast_addr: multicast IP address to send to - * sendto_port: port number to send multicast traffic to - * listen_port: port number on which the mcastsend can receive data - * - * f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667 - */ -extern struct udpclient_pas *udpclient_pas; -#ifdef PICO_SUPPORT_MCAST -void app_mcastsend(char *arg) -{ - char *maddr = NULL, *laddr = NULL, *lport = NULL, *sport = NULL; - uint16_t sendto_port = 0; - union pico_address inaddr_link = { - 0 - }, inaddr_mcast = { - 0 - }; - char *new_arg = NULL, *p = NULL, *nxt = arg; - struct pico_ip_mreq mreq = ZERO_MREQ; - - /* start of parameter parsing */ - if (nxt) { - nxt = cpy_arg(&laddr, nxt); - if (laddr) { - pico_string_to_ipv4(laddr, &inaddr_link.ip4.addr); - } else { - goto out; - } - } else { - /* no arguments */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&maddr, nxt); - if (maddr) { - pico_string_to_ipv4(maddr, &inaddr_mcast.ip4.addr); - } else { - goto out; - } - } else { - /* missing multicast address */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&sport, nxt); - if (sport && atoi(sport)) { - sendto_port = short_be(atoi(sport)); - } else { - /* incorrect send_port */ - goto out; - } - } else { - /* missing send_port */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - /* unused at this moment */ - /* listen_port = short_be(atoi(lport)); */ - } else { - /* incorrect listen_port */ - goto out; - } - } else { - /* missing listen_port */ - goto out; - } - - picoapp_dbg("\n%s: mcastsend started. Sending packets to %08X:%u\n\n", __FUNCTION__, long_be(inaddr_mcast.addr), short_be(sendto_port)); - - /* udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops] */ - new_arg = calloc(1, strlen(maddr) + 1 + strlen(sport) + 1 + strlen(lport) + strlen(":64:10:5:") + 1); - p = strcat(new_arg, maddr); - p = strcat(p + strlen(maddr), ":"); - p = strcat(p + 1, sport); - p = strcat(p + strlen(sport), ":"); - p = strcat(p + 1, lport); - p = strcat(p + strlen(lport), ":64:10:5:"); - - app_udpclient(new_arg); - free(new_arg); - - mreq.mcast_group_addr = inaddr_mcast; - mreq.mcast_link_addr = inaddr_link; - if(pico_socket_setoption(udpclient_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - picoapp_dbg("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err)); - exit(1); - } - - /* free strdups */ - if (maddr) - free(maddr); - - if (laddr) - free(laddr); - - if (lport) - free(lport); - - if (sport) - free(sport); - - return; - -out: - picoapp_dbg("mcastsend expects the following format: mcastsend:link_addr:mcast_addr:sendto_port:listen_port\n"); - exit(255); -} -#else -void app_mcastsend(char *arg) -{ - picoapp_dbg("ERROR: PICO_SUPPORT_MCAST disabled\n"); - return; -} -#endif -/*** END Multicast SEND ***/ diff --git a/ext/picotcp/test/examples/natbox.c b/ext/picotcp/test/examples/natbox.c deleted file mode 100644 index 1f54ecb..0000000 --- a/ext/picotcp/test/examples/natbox.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "utils.h" -#include -#include - -/*** START NATBOX ***/ -void app_natbox(char *arg) -{ - char *dest = NULL; - struct pico_ip4 ipdst, pub_addr, priv_addr; - struct pico_ipv4_link *link; - - cpy_arg(&dest, arg); - if (!dest) { - fprintf(stderr, "natbox needs the following format: natbox:dst_addr\n"); - exit(255); - } - - pico_string_to_ipv4(dest, &ipdst.addr); - link = pico_ipv4_link_get(&ipdst); - if (!link) { - fprintf(stderr, "natbox: Destination not found.\n"); - exit(255); - } - - pico_ipv4_nat_enable(link); - pico_string_to_ipv4("10.50.0.10", &pub_addr.addr); - pico_string_to_ipv4("10.40.0.08", &priv_addr.addr); - pico_ipv4_port_forward(pub_addr, short_be(5555), priv_addr, short_be(6667), PICO_PROTO_UDP, PICO_NAT_PORT_FORWARD_ADD); - fprintf(stderr, "natbox: started.\n"); -} -/*** END NATBOX ***/ diff --git a/ext/picotcp/test/examples/noop.c b/ext/picotcp/test/examples/noop.c deleted file mode 100644 index d7dd5a4..0000000 --- a/ext/picotcp/test/examples/noop.c +++ /dev/null @@ -1,11 +0,0 @@ -/* NOOP */ -#include -void app_noop(void) -{ - while(1) { - pico_stack_tick(); - usleep(2000); - } -} - -/* END NOOP */ diff --git a/ext/picotcp/test/examples/ping.c b/ext/picotcp/test/examples/ping.c deleted file mode 100644 index 7d33709..0000000 --- a/ext/picotcp/test/examples/ping.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "utils.h" -#include -#include -#include -#include -/*** START PING ***/ -#ifdef PICO_SUPPORT_PING -#define NUM_PING 10 - -void cb_ping(struct pico_icmp4_stats *s) -{ - char host[30]; - pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("%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); - if (s->seq >= NUM_PING) - exit(0); - } else { - dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err); - exit(1); - } -} - -#ifdef PICO_SUPPORT_IPV6 -void cb_ping6(struct pico_icmp6_stats *s) -{ - char host[50]; - pico_ipv6_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("%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); - if (s->seq >= NUM_PING) - exit(0); - } else { - dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err); - exit(1); - } -} -#endif - -void ping_abort_timer(pico_time now, void *_id) -{ - int *id = (int *) _id; - printf("Ping: aborting...\n"); - if (!IPV6_MODE) - pico_icmp4_ping_abort(*id); - -#ifdef PICO_SUPPORT_IPV6 - else - pico_icmp6_ping_abort(*id); -#endif -} - -void app_ping(char *arg) -{ - char *dest = NULL; - char *next = NULL; - char *abort = NULL; - char *delay = NULL; - char *asize = NULL; - int initial_delay = 0; - struct pico_ip6 dst; - static int id; - int timeout = 0; - int size = 64; - - next = cpy_arg(&dest, arg); - if (!dest) { - fprintf(stderr, "ping needs the following format: ping:dst_addr:[size:[abort after N sec:[wait N sec before start]]]\n"); - exit(255); - } - pico_string_to_ipv6(dest, dst.addr); - if (next) { - next = cpy_arg(&asize, next); - size = atoi(asize); - free(asize); - if (size <= 0) { - size = 64; /* Default */ - } - } - - if (next) { - next = cpy_arg(&abort, next); - if (strlen(abort) > 0) { - printf("Got arg: '%s'\n", abort); - timeout = atoi(abort); - if (timeout < 0) { - fprintf(stderr, "ping needs the following format: ping:dst_addr:[size:[abort after N sec:[wait N sec before start]]]\n"); - exit(255); - } - printf("Aborting ping after %d seconds\n", timeout); - } - } - - if (next) { - next = cpy_arg(&delay, next); - if (strlen(delay) > 0) { - initial_delay = atoi(delay); - if (initial_delay > 0) { - printf("Initial delay: %d seconds\n", initial_delay); - initial_delay = PICO_TIME_MS() + initial_delay * 1000; - while (PICO_TIME_MS() < initial_delay) { - pico_stack_tick(); - usleep(10000); - } - } - } - free(delay); - } - printf("Starting ping.\n"); - - if (!IPV6_MODE) - id = pico_icmp4_ping(dest, NUM_PING, 1000, 10000, size, cb_ping); - -#ifdef PICO_SUPPORT_IPV6 - else - id = pico_icmp6_ping(dest, NUM_PING, 1000, 10000, size, cb_ping6, pico_ipv6_source_dev_find(&dst)); -#endif - if (timeout > 0) { - printf("Adding abort timer after %d seconds for id %d\n", timeout, id); - if (!pico_timer_add(timeout * 1000, ping_abort_timer, &id)) { - printf("Failed to set ping abort timeout, aborting ping\n"); - ping_abort_timer((pico_time)0, &id); - exit(1); - } - } - - /* free copied args */ - if (dest) - free(dest); - - if (abort) - free(abort); -} -#endif -/*** END PING ***/ - diff --git a/ext/picotcp/test/examples/slaacv4.c b/ext/picotcp/test/examples/slaacv4.c deleted file mode 100644 index a4ca62d..0000000 --- a/ext/picotcp/test/examples/slaacv4.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "utils.h" -#include -#include -/*** START SLAACV4 ***/ - -void ping_callback_slaacv4(struct pico_icmp4_stats *s) -{ - char host[30] = { }; - - pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("SLAACV4: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", s->size, host, - s->seq, (long unsigned int)s->time); - if (s->seq >= 3) { - dbg("SLAACV4: TEST SUCCESS!\n"); - pico_slaacv4_unregisterip(); - exit(0); - } - } else { - dbg("SLAACV4: ping %lu to %s error %d\n", s->seq, host, s->err); - dbg("SLAACV4: TEST FAILED!\n"); - exit(1); - } -} - -void slaacv4_cb(struct pico_ip4 *ip, uint8_t code) -{ - char dst[16] = "169.254.22.5"; - printf("SLAACV4 CALLBACK ip:0x%X code:%d \n", ip->addr, code); - if (code == 0) - { -#ifdef PICO_SUPPORT_PING - pico_icmp4_ping(dst, 3, 1000, 5000, 32, ping_callback_slaacv4); -#else - exit(0); -#endif - } - else - { - exit(255); - } - -} - - -void app_slaacv4(char *arg) -{ - char *sdev = NULL; - char *nxt = arg; - struct pico_device *dev = NULL; - - if (!nxt) - exit(255); - - while (nxt) { - if (nxt) { - nxt = cpy_arg(&sdev, nxt); - if(!sdev) { - exit(255); - } - } - } - dev = pico_get_device(sdev); - free(sdev); - if(dev == NULL) { - printf("%s: error getting device %s: %s\n", __FUNCTION__, dev->name, strerror(pico_err)); - exit(255); - } - - pico_slaacv4_claimip(dev, slaacv4_cb); -} -/*** END SLAACv4 ***/ diff --git a/ext/picotcp/test/examples/sntp.c b/ext/picotcp/test/examples/sntp.c deleted file mode 100644 index 4a55dd3..0000000 --- a/ext/picotcp/test/examples/sntp.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "utils.h" -#include -/*** START SNTP ***/ - -#ifdef PICO_SUPPORT_SNTP_CLIENT - -void sntp_timeout(pico_time __attribute__((unused)) now, void *arg) -{ - struct pico_timeval ptv; - struct timeval tv; - pico_sntp_gettimeofday(&ptv); - gettimeofday(&tv, NULL); - printf("Linux sec: %u, msec: %u\n", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec / 1000); - printf("Picotcp sec: %u, msec: %u\n", (unsigned int)ptv.tv_sec, (unsigned int)ptv.tv_msec); - printf("SNTP test succesfull!\n"); - exit(0); -} - -void cb_synced(pico_err_t status) -{ - if(status == PICO_ERR_ENETDOWN) { - printf("SNTP: Cannot resolve ntp server name\n"); - exit(1); - } else if (status == PICO_ERR_ETIMEDOUT) { - printf("SNTP: Timed out, did not receive ntp packet from server\n"); - exit(1); - } else if (status == PICO_ERR_EINVAL) { - printf("SNTP: Conversion error\n"); - exit(1); - } else if (status == PICO_ERR_ENOTCONN) { - printf("SNTP: Socket error\n"); - exit(1); - } else if (status == PICO_ERR_NOERR) { - if (!pico_timer_add(2000, sntp_timeout, NULL)) { - printf("SNTP: Failed to start timeout timer, exiting program \n"); - exit(1); - } - } else { - printf("SNTP: Invalid status received in cb_synced\n"); - exit(1); - } -} - -void app_sntp(char *servername) -{ - struct pico_timeval tv; - printf("Starting SNTP query towards %s\n", servername); - if(pico_sntp_gettimeofday(&tv) == 0) - printf("Wrongly succesfull gettimeofday\n"); - else - printf("Unsuccesfull gettimeofday (not synced)\n"); - - if(pico_sntp_sync(servername, &cb_synced) == 0) - printf("Succesfull sync call!\n"); - else - printf("Error in sync\n"); -} -#endif -/*** END SNTP ***/ diff --git a/ext/picotcp/test/examples/tcpbench.c b/ext/picotcp/test/examples/tcpbench.c deleted file mode 100644 index 39b29a4..0000000 --- a/ext/picotcp/test/examples/tcpbench.c +++ /dev/null @@ -1,320 +0,0 @@ -#include "utils.h" -#include -#include -#include -/*** START TCP BENCH ***/ -#define TCP_BENCH_TX 1 -#define TCP_BENCH_RX 2 -#define TCP_BENCH_TX_FOREVER 3 -static char *buffer1; -static char *buffer0; - -int tcpbench_mode = 0; -struct pico_socket *tcpbench_sock = NULL; -static pico_time tcpbench_time_start, tcpbench_time_end; - -void cb_tcpbench(uint16_t ev, struct pico_socket *s) -{ - static int closed = 0; - static unsigned long count = 0; - uint8_t recvbuf[1500]; - uint16_t port; - char peer[200]; - /* struct pico_socket *sock_a; */ - - static int tcpbench_wr_size = 0; - static int tcpbench_rd_size = 0; - int tcpbench_w = 0; - int tcpbench_r = 0; - double tcpbench_time = 0; - - count++; - - if (ev & PICO_SOCK_EV_RD) { - do { - /* read data, but discard */ - tcpbench_r = pico_socket_read(s, recvbuf, 1500); - if (tcpbench_r > 0) { - tcpbench_rd_size += tcpbench_r; - } - } while (tcpbench_r > 0); - if (tcpbench_time_start == 0) - tcpbench_time_start = PICO_TIME_MS(); - - printf("tcpbench_rd_size = %d \r", tcpbench_rd_size); - } - - if (ev & PICO_SOCK_EV_CONN) { - if (!IPV6_MODE) { - struct pico_ip4 orig; - if (tcpbench_mode == TCP_BENCH_TX || tcpbench_mode == TCP_BENCH_TX_FOREVER) { - printf("tcpbench> Connection established with server.\n"); - } else if (tcpbench_mode == TCP_BENCH_RX) { - /* sock_a = pico_socket_accept(s, &orig, &port); */ - pico_socket_accept(s, &orig, &port); - pico_ipv4_to_string(peer, orig.addr); - printf("tcpbench> Connection established with %s:%d.\n", peer, short_be(port)); - } - } else { - struct pico_ip6 orig; - if (tcpbench_mode == TCP_BENCH_TX || tcpbench_mode == TCP_BENCH_TX_FOREVER) { - printf("tcpbench> Connection established with server.\n"); - } else if (tcpbench_mode == TCP_BENCH_RX) { - /* sock_a = pico_socket_accept(s, &orig, &port); */ - pico_socket_accept(s, &orig, &port); -#ifdef PICO_SUPPORT_IPV6 - pico_ipv6_to_string(peer, orig.addr); - printf("tcpbench> Connection established with [%s]:%d.\n", peer, short_be(port)); -#endif - } - } - } - - if (ev & PICO_SOCK_EV_FIN) { - printf("tcpbench> Socket closed. Exit normally. \n"); - if (tcpbench_mode == TCP_BENCH_RX) { - tcpbench_time_end = PICO_TIME_MS(); - tcpbench_time = (tcpbench_time_end - tcpbench_time_start) / 1000.0; /* get number of seconds */ - printf("tcpbench> received %d bytes in %lf seconds\n", tcpbench_rd_size, tcpbench_time); - printf("tcpbench> average read throughput %lf kbit/sec\n", ((tcpbench_rd_size * 8.0) / tcpbench_time) / 1000); - pico_socket_shutdown(s, PICO_SHUT_WR); - printf("tcpbench> Called shutdown write, ev = %d\n", ev); - } - - if (!pico_timer_add(5000, deferred_exit, NULL)) { - printf("tcpbench> Failed to start exit timer, exiting now\n"); - exit(1); - } - } - - if (ev & PICO_SOCK_EV_ERR) { - printf("tcpbench> ---- Socket Error received: %s. Bailing out.\n", strerror(pico_err)); - if (!pico_err == PICO_ERR_ECONNRESET) { - if (pico_timer_add(5000, deferred_exit, NULL)) { - printf("tcpbench> Failed to start exit timer, exiting now\n"); - exit(1); - } - } - else { - printf("tcpbench> ---- Socket Error: '%s'. Was unexpected! Something went wrong.\n", strerror(pico_err)); - exit(2); - } - } - - if (ev & PICO_SOCK_EV_CLOSE) { - printf("tcpbench> event close\n"); - if (tcpbench_mode == TCP_BENCH_RX) { - pico_socket_close(s); - printf("tcpbench> Called shutdown write, ev = %d\n", ev); - } else if (tcpbench_mode == TCP_BENCH_TX || tcpbench_mode == TCP_BENCH_TX_FOREVER) { - pico_socket_close(s); - return; - } - } - - if (ev & PICO_SOCK_EV_WR) { - if (((tcpbench_wr_size < TCPSIZ) && (tcpbench_mode == TCP_BENCH_TX)) || tcpbench_mode == TCP_BENCH_TX_FOREVER) { - do { - tcpbench_w = pico_socket_write(tcpbench_sock, buffer0 + (tcpbench_wr_size % TCPSIZ), TCPSIZ - (tcpbench_wr_size % TCPSIZ)); - if (tcpbench_w > 0) { - tcpbench_wr_size += tcpbench_w; - /* printf("tcpbench> SOCKET WRITTEN - %d\n",tcpbench_w); */ - } else { - /* printf("pico_socket_write returned %d\n", tcpbench_w); */ - } - - if (tcpbench_time_start == 0) - tcpbench_time_start = PICO_TIME_MS(); - } while(tcpbench_w > 0); - printf("tcpbench_wr_size = %d \r", tcpbench_wr_size); - } else { - if (!closed && tcpbench_mode == TCP_BENCH_TX) { - tcpbench_time_end = PICO_TIME_MS(); - pico_socket_shutdown(s, PICO_SHUT_WR); - printf("tcpbench> TCPSIZ written\n"); - printf("tcpbench> Called shutdown()\n"); - tcpbench_time = (tcpbench_time_end - tcpbench_time_start) / 1000.0; /* get number of seconds */ - printf("tcpbench> Transmitted %u bytes in %lf seconds\n", TCPSIZ, tcpbench_time); - printf("tcpbench> average write throughput %lf kbit/sec\n", ((TCPSIZ * 8.0) / tcpbench_time) / 1000); - closed = 1; - } - } - } -} - -void app_tcpbench(char *arg) -{ - struct pico_socket *s; - char *dport = NULL; - char *dest = NULL; - char *mode = NULL; - char *nagle = NULL; - int port = 0, i; - uint16_t port_be = 0; - char *nxt; - char *sport = NULL; - int nagle_off = 1; - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } inaddr_any = { - .ip4 = {0}, .ip6 = {{0}} - }; - - nxt = cpy_arg(&mode, arg); - - if ((*mode == 't') || (*mode == 'f')) { /* TEST BENCH SEND MODE */ - if (*mode == 't') - tcpbench_mode = TCP_BENCH_TX; - else - tcpbench_mode = TCP_BENCH_TX_FOREVER; - - printf("tcpbench> TX\n"); - - nxt = cpy_arg(&dest, nxt); - if (!dest) { - fprintf(stderr, "tcpbench send needs the following format: tcpbench:tx:dst_addr[:dport][:n] -- 'n' is for nagle\n"); - exit(255); - } - - printf ("+++ Dest is %s\n", dest); - if (nxt) { - printf("Next arg: %s\n", nxt); - nxt = cpy_arg(&dport, nxt); - printf("Dport: %s\n", dport); - } - - if (nxt) { - printf("Next arg: %s\n", nxt); - nxt = cpy_arg(&nagle, nxt); - printf("nagle: %s\n", nagle); - if (strlen(nagle) == 1 && nagle[0] == 'n') { - nagle_off = 0; - printf("Nagle algorithm enabled\n"); - } - } - - if (dport) { - port = atoi(dport); - port_be = short_be((uint16_t)port); - } - - if (port == 0) { - port_be = short_be(5555); - } - - buffer0 = malloc(TCPSIZ); - buffer1 = malloc(TCPSIZ); - printf("Buffer1 (%p)\n", buffer1); - for (i = 0; i < TCPSIZ; i++) { - char c = (i % 26) + 'a'; - buffer0[i] = c; - } - memset(buffer1, 'a', TCPSIZ); - printf("tcpbench> Connecting to: %s:%d\n", dest, short_be(port_be)); - - if (!IPV6_MODE) { - struct pico_ip4 server_addr; - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpbench); - if (!s) - exit(1); - - pico_socket_setoption(s, PICO_TCP_NODELAY, &nagle_off); - - /* NOTE: used to set a fixed local port and address - local_port = short_be(6666); - pico_string_to_ipv4("10.40.0.11", &local_addr.addr); - pico_socket_bind(s, &local_addr, &local_port);*/ - - pico_string_to_ipv4(dest, &server_addr.addr); - pico_socket_connect(s, &server_addr, port_be); - } else { - struct pico_ip6 server_addr; - s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpbench); - if (!s) - exit(1); - - pico_socket_setoption(s, PICO_TCP_NODELAY, &nagle_off); - - /* NOTE: used to set a fixed local port and address - local_port = short_be(6666); - pico_string_to_ipv4("10.40.0.11", &local_addr.addr); - pico_socket_bind(s, &local_addr, &local_port);*/ -#ifdef PICO_SUPPORT_IPV6 - pico_string_to_ipv6(dest, server_addr.addr); - pico_socket_connect(s, &server_addr, port_be); -#endif - - } - - } else if (*mode == 'r') { /* TEST BENCH RECEIVE MODE */ - int ret; - tcpbench_mode = TCP_BENCH_RX; - printf("tcpbench> RX\n"); - - cpy_arg(&sport, nxt); - if (!sport) { - fprintf(stderr, "tcpbench receive needs the following format: tcpbench:rx[:dport]\n"); - exit(255); - } - - if (sport) { - printf("s-port is %s\n", sport); - port = atoi(sport); - port_be = short_be((uint16_t)port); - printf("tcpbench> Got port %d\n", port); - free(sport); - } - - if (port == 0) { - port_be = short_be(5555); - } - - printf("tcpbench> OPEN\n"); - if (!IPV6_MODE) - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpbench); - else - s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpbench); - - if (!s) - exit(1); - - printf("tcpbench> BIND\n"); - if (!IPV6_MODE) - ret = pico_socket_bind(s, &inaddr_any.ip4, &port_be); - else - ret = pico_socket_bind(s, &inaddr_any.ip6, &port_be); - - if (ret < 0) { - printf("tcpbench> BIND failed because %s\n", strerror(pico_err)); - exit(1); - } - - printf("tcpbench> LISTEN\n"); - if (pico_socket_listen(s, 40) != 0) - exit(1); - - printf("tcpbench> listening port %u ...\n", short_be(port_be)); - } else { - printf("tcpbench> wrong mode argument\n"); - exit(1); - } - - tcpbench_sock = s; - - /* free strdups */ - if (dport) - free(dport); - - if (dest) - free (dest); - - if (mode) - free (mode); - - if (nagle) - free (nagle); - - return; -} -/*** END TCP BENCH ***/ diff --git a/ext/picotcp/test/examples/tcpclient.c b/ext/picotcp/test/examples/tcpclient.c deleted file mode 100644 index e81bddd..0000000 --- a/ext/picotcp/test/examples/tcpclient.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "utils.h" -#include -#include -#include -/*** START TCP CLIENT ***/ -static char *buffer1; -static char *buffer0; - -void compare_results(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg) -{ -#ifdef CONSISTENCY_CHECK /* TODO: Enable */ - int i; - printf("Calculating result.... (%p)\n", buffer1); - - if (memcmp(buffer0, buffer1, TCPSIZ) == 0) - exit(0); - - for (i = 0; i < TCPSIZ; i++) { - if (buffer0[i] != buffer1[i]) { - fprintf(stderr, "Error at byte %d - %c!=%c\n", i, buffer0[i], buffer1[i]); - exit(115); - } - } -#endif - exit(0); - -} - -void cb_tcpclient(uint16_t ev, struct pico_socket *s) -{ - static int w_size = 0; - static int r_size = 0; - static int closed = 0; - int r, w; - static unsigned long count = 0; - - count++; - picoapp_dbg("tcpclient> wakeup %lu, event %u\n", count, ev); - - if (ev & PICO_SOCK_EV_RD) { - do { - r = pico_socket_read(s, buffer1 + r_size, TCPSIZ - r_size); - if (r > 0) { - r_size += r; - picoapp_dbg("SOCKET READ - %d\n", r_size); - } - - if (r < 0) - exit(5); - } while(r > 0); - } - - if (ev & PICO_SOCK_EV_CONN) { - printf("Connection established with server.\n"); - } - - if (ev & PICO_SOCK_EV_FIN) { - printf("Socket closed. Exit normally. \n"); - if (!pico_timer_add(2000, compare_results, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - } - - if (ev & PICO_SOCK_EV_ERR) { - printf("Socket error received: %s. Bailing out.\n", strerror(pico_err)); - exit(1); - } - - if (ev & PICO_SOCK_EV_CLOSE) { - printf("Socket received close from peer - Wrong case if not all client data sent!\n"); - pico_socket_close(s); - return; - } - - if (ev & PICO_SOCK_EV_WR) { - if (w_size < TCPSIZ) { - do { - w = pico_socket_write(s, buffer0 + w_size, TCPSIZ - w_size); - if (w > 0) { - w_size += w; - picoapp_dbg("SOCKET WRITTEN - %d\n", w_size); - if (w < 0) - exit(5); - } - } while(w > 0); - } else { -#ifdef INFINITE_TCPTEST - w_size = 0; - return; -#endif - if (!closed) { - pico_socket_shutdown(s, PICO_SHUT_WR); - printf("Called shutdown()\n"); - closed = 1; - } - } - } -} - -void app_tcpclient(char *arg) -{ - char *daddr = NULL, *dport = NULL; - char *nxt = arg; - uint16_t send_port = 0, listen_port = short_be(5555); - int i = 0, ret = 0, yes = 1; - struct pico_socket *s = NULL; - union pico_address dst = { - .ip4 = {0}, .ip6 = {{0}} - }; - union pico_address inaddr_any = { - .ip4 = {0}, .ip6 = {{0}} - }; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&daddr, arg); - if (daddr) { - if (!IPV6_MODE) - pico_string_to_ipv4(daddr, &dst.ip4.addr); - - #ifdef PICO_SUPPORT_IPV6 - else - pico_string_to_ipv6(daddr, dst.ip6.addr); - #endif - } else { - goto out; - } - } else { - /* missing dest_addr */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&dport, nxt); - if (dport && atoi(dport)) { - send_port = short_be(atoi(dport)); - } else { - goto out; - } - } else { - /* missing send_port */ - goto out; - } - - /* end of argument parsing */ - - buffer0 = malloc(TCPSIZ); - buffer1 = malloc(TCPSIZ); - printf("Buffer1 (%p)\n", buffer1); - for (i = 0; i < TCPSIZ; i++) { - char c = (i % 26) + 'a'; - buffer0[i] = c; - } - memset(buffer1, 'a', TCPSIZ); - - printf("Connecting to: %s:%d\n", daddr, short_be(send_port)); - - if (!IPV6_MODE) - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpclient); - else - s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpclient); - - if (!s) { - printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); - exit(1); - } - - pico_socket_setoption(s, PICO_TCP_NODELAY, &yes); - - if (!IPV6_MODE) - ret = pico_socket_bind(s, &inaddr_any.ip4, &listen_port); - else - ret = pico_socket_bind(s, &inaddr_any.ip6, &listen_port); - - if (ret < 0) { - printf("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err)); - exit(1); - } - - if (!IPV6_MODE) - ret = pico_socket_connect(s, &dst.ip4, send_port); - else - ret = pico_socket_connect(s, &dst.ip6, send_port); - - if (ret < 0) { - printf("%s: error connecting to %s:%u: %s\n", __FUNCTION__, daddr, short_be(send_port), strerror(pico_err)); - exit(1); - } - - return; - -out: - fprintf(stderr, "tcpclient expects the following format: tcpclient:dest_addr:dest_port\n"); - exit(255); -} -/*** END TCP CLIENT ***/ diff --git a/ext/picotcp/test/examples/tcpecho.c b/ext/picotcp/test/examples/tcpecho.c deleted file mode 100644 index b109d9c..0000000 --- a/ext/picotcp/test/examples/tcpecho.c +++ /dev/null @@ -1,178 +0,0 @@ -#include "utils.h" -#include -#include -/*** START TCP ECHO ***/ -#define BSIZE (1024 * 10) -static char recvbuf[BSIZE]; -static int pos = 0, len = 0; -static int flag = 0; - -int send_tcpecho(struct pico_socket *s) -{ - int w, ww = 0; - if (len > pos) { - do { - w = pico_socket_write(s, recvbuf + pos, len - pos); - if (w > 0) { - pos += w; - ww += w; - if (pos >= len) { - pos = 0; - len = 0; - } - } - } while((w > 0) && (pos < len)); - } - - return ww; -} - -void cb_tcpecho(uint16_t ev, struct pico_socket *s) -{ - int r = 0; - - picoapp_dbg("tcpecho> wakeup ev=%u\n", ev); - - if (ev & PICO_SOCK_EV_RD) { - if (flag & PICO_SOCK_EV_CLOSE) - printf("SOCKET> EV_RD, FIN RECEIVED\n"); - - while (len < BSIZE) { - r = pico_socket_read(s, recvbuf + len, BSIZE - len); - if (r > 0) { - len += r; - flag &= ~(PICO_SOCK_EV_RD); - } else { - flag |= PICO_SOCK_EV_RD; - break; - } - } - if (flag & PICO_SOCK_EV_WR) { - flag &= ~PICO_SOCK_EV_WR; - send_tcpecho(s); - } - } - - if (ev & PICO_SOCK_EV_CONN) { - uint32_t ka_val = 0; - struct pico_socket *sock_a = { - 0 - }; - struct pico_ip4 orig = { - 0 - }; - uint16_t port = 0; - char peer[30] = { - 0 - }; - int yes = 1; - - sock_a = pico_socket_accept(s, &orig, &port); - pico_ipv4_to_string(peer, orig.addr); - printf("Connection established with %s:%d.\n", peer, short_be(port)); - pico_socket_setoption(sock_a, PICO_TCP_NODELAY, &yes); - /* Set keepalive options */ - ka_val = 5; - pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPCNT, &ka_val); - ka_val = 30000; - pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPIDLE, &ka_val); - ka_val = 5000; - pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPINTVL, &ka_val); - } - - if (ev & PICO_SOCK_EV_FIN) { - printf("Socket closed. Exit normally. \n"); - if (!pico_timer_add(2000, deferred_exit, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - } - - if (ev & PICO_SOCK_EV_ERR) { - printf("Socket error received: %s. Bailing out.\n", strerror(pico_err)); - exit(1); - } - - if (ev & PICO_SOCK_EV_CLOSE) { - printf("Socket received close from peer.\n"); - if (flag & PICO_SOCK_EV_RD) { - pico_socket_shutdown(s, PICO_SHUT_WR); - printf("SOCKET> Called shutdown write, ev = %d\n", ev); - } - } - - if (ev & PICO_SOCK_EV_WR) { - r = send_tcpecho(s); - if (r == 0) - flag |= PICO_SOCK_EV_WR; - else - flag &= (~PICO_SOCK_EV_WR); - } -} - -void app_tcpecho(char *arg) -{ - char *nxt = arg; - char *lport = NULL; - uint16_t listen_port = 0; - int ret = 0, yes = 1; - struct pico_socket *s = NULL; - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } inaddr_any = { - .ip4 = {0}, .ip6 = {{0}} - }; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - listen_port = short_be(atoi(lport)); - } else { - goto out; - } - } else { - /* missing listen_port */ - goto out; - } - - /* end of argument parsing */ - - if (!IPV6_MODE) - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpecho); - else - s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpecho); - - if (!s) { - printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); - exit(1); - } - - pico_socket_setoption(s, PICO_TCP_NODELAY, &yes); - - - - if (!IPV6_MODE) - ret = pico_socket_bind(s, &inaddr_any.ip4, &listen_port); - else - ret = pico_socket_bind(s, &inaddr_any.ip6, &listen_port); - - if (ret < 0) { - printf("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err)); - exit(1); - } - - if (pico_socket_listen(s, 40) != 0) { - printf("%s: error listening on port %u\n", __FUNCTION__, short_be(listen_port)); - exit(1); - } - - printf("Launching PicoTCP echo server\n"); - return; - -out: - fprintf(stderr, "tcpecho expects the following format: tcpecho:listen_port\n"); - exit(255); -} -/*** END TCP ECHO ***/ diff --git a/ext/picotcp/test/examples/tftp.c b/ext/picotcp/test/examples/tftp.c deleted file mode 100644 index d691ca4..0000000 --- a/ext/picotcp/test/examples/tftp.c +++ /dev/null @@ -1,485 +0,0 @@ -#include "utils.h" -#include -#include -#include -#include -#include -#include -#include -#include - -/* Let's use linux fs */ -#include - -#include - -/*** START TFTP ***/ -#ifdef PICO_SUPPORT_TFTP -#define TFTP_MODE_SRV 0 -#define TFTP_MODE_CLI 1 -#define TFTP_MODE_PSH 2 -#define TFTP_TX_COUNT 2000 -#define TFTP_PAYLOAD_SIZE 512 -unsigned char tftp_txbuf[TFTP_PAYLOAD_SIZE]; -static uint16_t family; - -struct command_t { - char operation; - char *filename; - union pico_address server_address; - struct command_t *next; -}; - -struct note_t { - char *filename; - int fd; - char direction; - int32_t filesize; - struct note_t *next; -}; - -struct note_t *clipboard = NULL; - -struct note_t *add_note(const char *filename, int fd, char direction) -{ - struct note_t *note = PICO_ZALLOC(sizeof(struct note_t)); - - note->filename = strdup(filename); - note->fd = fd; - note->direction = direction; - note->filesize = 0; - note->next = clipboard; - clipboard = note; - return note; -} - -void del_note(struct note_t *note) -{ - struct note_t *prev; - - if (note == clipboard) - { - clipboard = clipboard->next; - if (note->filename) - free (note->filename); - - PICO_FREE(note); - } else { - for (prev = clipboard; prev->next; prev = prev->next) - if (prev->next == note) { - prev->next = note->next; - if (note->filename) - free (note->filename); - - PICO_FREE(note); - break; - } - - } -} - -struct command_t *add_command(struct command_t *commands, char operation, - char *filename, union pico_address *server_address) -{ - struct command_t *command = PICO_ZALLOC(sizeof(struct command_t)); - - command->operation = operation; - command->filename = filename; - memcpy(&command->server_address, server_address, sizeof(union pico_address)); - command->next = commands; - return command; -} - -int32_t get_filesize(const char *filename) -{ - int ret; - struct stat buf; - - ret = stat(filename, &buf); - if (ret) - return -1; - - return buf.st_size; -} - -struct note_t *setup_transfer(char operation, const char *filename) -{ - int fd; - - printf("operation %c\n", operation); - fd = open(filename, (toupper(operation) == 'T') ? O_RDONLY : O_WRONLY | O_EXCL | O_CREAT, 0666); - if (fd < 0) { - perror("open"); - fprintf(stderr, "Unable to handle file %s\n", filename); - return NULL; - } - - return add_note(filename, fd, operation); -} - -int cb_tftp_tx(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg) -{ - struct note_t *note = (struct note_t *) arg; - - if (event != PICO_TFTP_EV_OK) { - fprintf(stderr, "TFTP: Error %" PRIu16 ": %s\n", event, block); - exit(1); - } - - len = read(note->fd, tftp_txbuf, PICO_TFTP_PAYLOAD_SIZE); - - if (len >= 0) { - note->filesize += len; - pico_tftp_send(session, tftp_txbuf, len); - if (len < PICO_TFTP_PAYLOAD_SIZE) { - printf("TFTP: file %s (%" PRId32 " bytes) TX transfer complete!\n", note->filename, note->filesize); - close(note->fd); - del_note(note); - } - } else { - perror("read"); - fprintf(stderr, "Filesystem error reading file %s, cancelling current transfer\n", note->filename); - pico_tftp_abort(session, TFTP_ERR_EACC, "Error on read"); - del_note(note); - } - - if (!clipboard) { - if (!pico_timer_add(3000, deferred_exit, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - } - - return len; -} - -int cb_tftp_tx_opt(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg) -{ - int ret; - int32_t filesize; - - if (event == PICO_TFTP_EV_OPT) { - ret = pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, &filesize); - if (ret) - printf("TFTP: Option filesize is not used\n"); - else - printf("TFTP: We expect to transmit %" PRId32 " bytes\n", filesize); - - event = PICO_TFTP_EV_OK; - } - - return cb_tftp_tx(session, event, block, len, arg); -} - -int cb_tftp_rx(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg) -{ - struct note_t *note = (struct note_t *) arg; - int ret; - - if (event != PICO_TFTP_EV_OK) { - fprintf(stderr, "TFTP: Error %" PRIu16 ": %s\n", event, block); - exit(1); - } - - if (!note) - return 0; - - note->filesize += len; - if (write(note->fd, block, len) < 0) { - perror("write"); - fprintf(stderr, "Filesystem error writing file %s, cancelling current transfer\n", note->filename); - pico_tftp_abort(session, TFTP_ERR_EACC, "Error on write"); - del_note(note); - } else { - if (len != PICO_TFTP_PAYLOAD_SIZE) { - printf("TFTP: file %s (%" PRId32 " bytes) RX transfer complete!\n", note->filename, note->filesize); - close(note->fd); - del_note(note); - } - } - - if (!clipboard) { - if (!pico_timer_add(3000, deferred_exit, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - } - - return len; -} - -int cb_tftp_rx_opt(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg) -{ - int ret; - int32_t filesize; - - if (event == PICO_TFTP_EV_OPT) { - ret = pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, &filesize); - if (ret) - printf("TFTP: Option filesize is not used\n"); - else - printf("TFTP: We expect to receive %" PRId32 " bytes\n", filesize); - - return 0; - } - - return cb_tftp_rx(session, event, block, len, arg); -} - -struct pico_tftp_session *make_session_or_die(union pico_address *addr, uint16_t family) -{ - struct pico_tftp_session *session; - - session = pico_tftp_session_setup(addr, family); - if (!session) { - fprintf(stderr, "TFTP: Error in session setup\n"); - exit(3); - } - - return session; -} - -struct note_t *transfer_prepare(struct pico_tftp_session **psession, char operation, const char *filename, union pico_address *addr, uint16_t family) -{ - struct note_t *note; - - note = setup_transfer(operation, filename); - *psession = make_session_or_die(addr, family); - return note; -} - -void start_rx(struct pico_tftp_session *session, const char *filename, uint16_t port, - int (*rx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg), - struct note_t *note) -{ - if (pico_tftp_start_rx(session, port, filename, rx_callback, note)) { - fprintf(stderr, "TFTP: Error in initialization\n"); - exit(1); - } -} - -void start_tx(struct pico_tftp_session *session, const char *filename, uint16_t port, - int (*tx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg), - struct note_t *note) -{ - if (pico_tftp_start_tx(session, port, filename, tx_callback, note)) { - fprintf(stderr, "TFTP: Error in initialization\n"); - exit(1); - } -} - -void tftp_listen_cb(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len) -{ - struct note_t *note; - struct pico_tftp_session *session; - - printf("TFTP listen callback (BASIC) from remote port %" PRIu16 ".\n", short_be(port)); - if (opcode == PICO_TFTP_RRQ) { - printf("Received TFTP get request for %s\n", filename); - note = transfer_prepare(&session, 't', filename, addr, family); - start_tx(session, filename, port, cb_tftp_tx, note); - } else if (opcode == PICO_TFTP_WRQ) { - printf("Received TFTP put request for %s\n", filename); - note = transfer_prepare(&session, 'r', filename, addr, family); - start_rx(session, filename, port, cb_tftp_rx, note); - } -} - -void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, uint16_t opcode, char *filename, int32_t len) -{ - struct note_t *note; - struct pico_tftp_session *session; - int options; - uint8_t timeout; - int32_t filesize; - int ret; - - printf("TFTP listen callback (OPTIONS) from remote port %" PRIu16 ".\n", short_be(port)); - /* declare the options we want to support */ - ret = pico_tftp_parse_request_args(filename, len, &options, &timeout, &filesize); - if (ret) - pico_tftp_reject_request(addr, port, TFTP_ERR_EOPT, "Malformed request"); - - if (opcode == PICO_TFTP_RRQ) { - printf("Received TFTP get request for %s\n", filename); - note = transfer_prepare(&session, 'T', filename, addr, family); - - if (options & PICO_TFTP_OPTION_TIME) - pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - - if (options & PICO_TFTP_OPTION_FILE) { - ret = get_filesize(filename); - if (ret < 0) { - pico_tftp_reject_request(addr, port, TFTP_ERR_ENOENT, "File not found"); - return; - } - - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); - } - - start_tx(session, filename, port, cb_tftp_tx_opt, note); - } else { /* opcode == PICO_TFTP_WRQ */ - printf("Received TFTP put request for %s\n", filename); - - note = transfer_prepare(&session, 'R', filename, addr, family); - if (options & PICO_TFTP_OPTION_TIME) - pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - - if (options & PICO_TFTP_OPTION_FILE) - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); - - start_rx(session, filename, port, cb_tftp_rx_opt, note); - } -} - -void print_usage(int exit_code) -{ - printf("\nUsage: tftp:OPTION:[OPTION]...\n" - "\nOtions can be repeated. Every option may be one of the following:\n" - "\ts\t\t\t starts the basic server (RFC1350)\n" - "\tS\t\t\t starts the server with option handling capability\n" - "\tt:file:ip\t\t PUT request (without options) for file to server ip\n" - "\tT:file:ip\t\t PUT request for file to server ip\n" - "\tr:file:ip\t\t GET request (without options) for file to server ip\n" - "\tR:file:ip\t\t GET request for file to server ip\n" - "Example:\n" - "\t\t tftp:S:T:firstFile:10.40.0.2:R:another.file:10.40.0.5:T:secondFile:10.40.0.2\n\n"); - exit(exit_code); -} - -struct command_t *parse_arguments_recursive(struct command_t *commands, char *arg) -{ - char *next; - char *operation; - char *filename; - char *address; - static union pico_address remote_address; - int ret; - struct command_t *new_cmd = NULL; - - if (!arg) - return commands; - - next = cpy_arg(&operation, arg); - switch (*operation) { - case 'S': - case 's': - filename = address = NULL; - break; - case 'T': - case 'R': - case 't': - case 'r': - if (!next) { - fprintf(stderr, "Incomplete client command %s (filename componet is missing)\n", arg); - return NULL; - } - - next = cpy_arg(&filename, next); - if (!next) { - fprintf(stderr, "Incomplete client command %s (address component is missing)\n", arg); - return NULL; - } - - next = cpy_arg(&address, next); - if (!IPV6_MODE) - ret = pico_string_to_ipv4(address, &remote_address.ip4.addr); - else - ret = pico_string_to_ipv6(address, remote_address.ip6.addr); - - if (ret < 0) { - fprintf(stderr, "Invalid IP address %s\n", address); - print_usage(2); - } - - if (address) - free(address); - - break; - default: - fprintf(stderr, "Invalid command %s\n", operation); - return NULL; - }; - - new_cmd = add_command(commands, *operation, filename, &remote_address); - free(operation); - return parse_arguments_recursive(new_cmd, next); -} - -struct command_t *parse_arguments(char *arg) -{ - struct command_t *reversed = parse_arguments_recursive(NULL, arg); - struct command_t *commands = NULL; - struct command_t *current; - - if (!reversed) { - fprintf(stderr, "Wrong command line!\n"); - print_usage(1); - } - - while (reversed) { - current = reversed; - reversed = reversed->next; - current->next = commands; - commands = current; - } - return commands; -} - -void app_tftp(char *arg) -{ - struct command_t *commands, *old_cmd; - struct note_t *note; - struct pico_tftp_session *session; - int is_server_enabled = 0; - int filesize; - - family = IPV6_MODE ? PICO_PROTO_IPV6 : PICO_PROTO_IPV4; - - commands = parse_arguments(arg); - while (commands) { - - if (toupper(commands->operation) != 'S') - note = transfer_prepare(&session, commands->operation, commands->filename, &commands->server_address, family); - - switch (commands->operation) { - case 'S': - case 's': - if (!is_server_enabled) { - pico_tftp_listen(PICO_PROTO_IPV4, (commands->operation == 'S') ? tftp_listen_cb_opt : tftp_listen_cb); - is_server_enabled = 1; - } - - break; - case 'T': - filesize = get_filesize(commands->filename); - if (filesize < 0) { - fprintf(stderr, "TFTP: unable to read size of file %s\n", commands->filename); - exit(3); - } - - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); - start_tx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_tx_opt, note); - break; - case 't': - start_tx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_tx, note); - break; - case 'R': - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0); - start_rx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_rx_opt, note); - break; - case 'r': - start_rx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_rx, note); - } - old_cmd = commands; - commands = commands->next; - if (old_cmd->filename) - free(old_cmd->filename); - - /* commands are allocated using PICO_ZALLOC, so use PICO_FREE */ - PICO_FREE(old_cmd); - } -} - -#endif -/* END TFTP */ diff --git a/ext/picotcp/test/examples/udp_client.c b/ext/picotcp/test/examples/udp_client.c deleted file mode 100644 index ded23bf..0000000 --- a/ext/picotcp/test/examples/udp_client.c +++ /dev/null @@ -1,290 +0,0 @@ -#include "utils.h" -#include -#include -#include - -/*** START UDP CLIENT ***/ -/* - * udpclient expects the following format: udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops] - * dest_addr: IP address to send datagrams to - * sendto_port: port number to send datagrams to - * listen_port [OPTIONAL]: port number on which the udpclient listens - * datasize [OPTIONAL]: size of the data given to the socket in one go - * loops [OPTIONAL]: number of intervals in which data is send - * subloops [OPTIONAL]: number of sends in one interval - * - * REMARK: once an optional parameter is given, all optional parameters need a value! - * - * f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a udpclient:10.40.0.3:6667:6667:1400:100:10 - */ - -struct udpclient_pas *udpclient_pas; - -static int exit_retry = 0; - -static void request_exit_echo(pico_time now, void *arg) -{ - struct pico_socket *s = (struct pico_socket *)arg; - char end[4] = "end"; - pico_socket_send(s, end, 4); - if (exit_retry++ > 3) { - if (!pico_timer_add(1000, deferred_exit, udpclient_pas)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - } else { - if (!pico_timer_add(1000, request_exit_echo, s)) { - printf("Failed to start request_exit_echo timer, sending request now\n"); - request_exit_echo((pico_time)0, NULL); - exit(1); - } - printf("%s: requested exit of echo\n", __FUNCTION__); - } -} - -void udpclient_send(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg) -{ - struct pico_socket *s = udpclient_pas->s; - char *buf = NULL; - int i = 0, w = 0; - static uint16_t loop = 0; - - if (++loop > udpclient_pas->loops) { - if (!pico_timer_add(1000, request_exit_echo, s)) { - printf("Failed to start request_exit_echo timer, sending request now\n"); - request_exit_echo((pico_time)0, NULL); - exit(1); - } - return; - } else { - buf = calloc(1, udpclient_pas->datasize); - if (!buf) { - printf("%s: no memory available\n", __FUNCTION__); - return; - } - - memset(buf, '1', udpclient_pas->datasize); - picoapp_dbg("%s: performing loop %u\n", __FUNCTION__, loop); - for (i = 0; i < udpclient_pas->subloops; i++) { - w = pico_socket_send(s, buf, udpclient_pas->datasize); - if (w <= 0) - break; - } - picoapp_dbg("%s: written %u byte(s) in each of %u subloops\n", __FUNCTION__, udpclient_pas->datasize, i); - free(buf); - } - - if (!pico_timer_add(100, udpclient_send, NULL)) { - printf("Failed to start send timer, sending exit request to echo and exiting\n"); - request_exit_echo((pico_time)0, NULL); - exit(1); - } -} - -void cb_udpclient(uint16_t ev, struct pico_socket *s) -{ - char *recvbuf = NULL; - int r = 0; - - if (ev & PICO_SOCK_EV_RD) { - recvbuf = calloc(1, udpclient_pas->datasize); - if (!recvbuf) { - printf("%s: no memory available\n", __FUNCTION__); - return; - } - - do { - r = pico_socket_recv(s, recvbuf, udpclient_pas->datasize); - } while ( r > 0); - free(recvbuf); - } - - if (ev == PICO_SOCK_EV_ERR) { - printf("Socket Error received. Bailing out.\n"); - free(udpclient_pas); - exit(7); - } -} - -void app_udpclient(char *arg) -{ - char *daddr = NULL, *lport = NULL, *sport = NULL, *s_datasize = NULL, *s_loops = NULL, *s_subloops = NULL; - char *nxt = arg; - char sinaddr_any[40] = { - 0 - }; - uint16_t listen_port = 0; - int ret = 0; - - udpclient_pas = calloc(1, sizeof(struct udpclient_pas)); - if (!udpclient_pas) { - printf("%s: no memory available\n", __FUNCTION__); - exit(255); - } - - udpclient_pas->s = NULL; - udpclient_pas->loops = 100; - udpclient_pas->subloops = 10; - udpclient_pas->datasize = 1400; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&daddr, arg); - if (daddr) { - if (!IPV6_MODE) - pico_string_to_ipv4(daddr, &udpclient_pas->dst.ip4.addr); - - #ifdef PICO_SUPPORT_IPV6 - else - pico_string_to_ipv6(daddr, udpclient_pas->dst.ip6.addr); - #endif - } else { - goto out; - } - } else { - /* missing dest_addr */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&sport, nxt); - if (sport && atoi(sport)) { - udpclient_pas->sport = short_be(atoi(sport)); - } else { - goto out; - } - } else { - /* missing send_port */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - listen_port = short_be(atoi(lport)); - } else { - goto out; - } - } else { - /* missing listen_port, use default */ - listen_port = 0; - } - - if (nxt) { - nxt = cpy_arg(&s_datasize, nxt); - if (s_datasize && atoi(s_datasize)) { - udpclient_pas->datasize = atoi(s_datasize); - } else { - goto out; - } - } else { - /* missing datasize, incomplete optional parameters? -> exit */ - if (lport) - goto out; - } - - if (nxt) { - nxt = cpy_arg(&s_loops, nxt); - if (s_loops && atoi(s_loops)) { - udpclient_pas->loops = atoi(s_loops); - } else { - goto out; - } - } else { - /* missing loops, incomplete optional parameters? -> exit */ - if (s_datasize) - goto out; - } - - if (nxt) { - nxt = cpy_arg(&s_subloops, nxt); - if (s_subloops && atoi(s_subloops)) { - udpclient_pas->subloops = atoi(s_subloops); - } else { - goto out; - } - } else { - /* missing subloops, incomplete optional parameters? -> exit */ - if (s_loops) - goto out; - } - - /* end of argument parsing */ - - if (!IPV6_MODE) - pico_ipv4_to_string(sinaddr_any, inaddr_any.addr); - - #ifdef PICO_SUPPORT_IPV6 - else - pico_ipv6_to_string(sinaddr_any, inaddr6_any.addr); - #endif - - if (!IPV6_MODE) - udpclient_pas->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpclient); - else - udpclient_pas->s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &cb_udpclient); - - if (!udpclient_pas->s) { - printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); - free(udpclient_pas); - exit(1); - } - - if (!IPV6_MODE) - ret = pico_socket_bind(udpclient_pas->s, &inaddr_any, &listen_port); - else - ret = pico_socket_bind(udpclient_pas->s, &inaddr6_any, &listen_port); - - if (ret < 0) { - free(udpclient_pas); - printf("%s: error binding socket to %s:%u: %s\n", __FUNCTION__, sinaddr_any, short_be(listen_port), strerror(pico_err)); - exit(1); - } - - if (!IPV6_MODE) - ret = pico_socket_connect(udpclient_pas->s, &udpclient_pas->dst.ip4, udpclient_pas->sport); - else - ret = pico_socket_connect(udpclient_pas->s, &udpclient_pas->dst.ip6, udpclient_pas->sport); - - if (ret < 0) { - printf("%s: error connecting to [%s]:%u: %s\n", __FUNCTION__, daddr, short_be(udpclient_pas->sport), strerror(pico_err)); - free(udpclient_pas); - exit(1); - } - - printf("\n%s: UDP client launched. Sending packets of %u bytes in %u loops and %u subloops to %s:%u\n\n", - __FUNCTION__, udpclient_pas->datasize, udpclient_pas->loops, udpclient_pas->subloops, daddr, short_be(udpclient_pas->sport)); - - if (!pico_timer_add(100, udpclient_send, NULL)) { - printf("Failed to start send timer, sending exit request to echo and exiting\n"); - request_exit_echo((pico_time)0, NULL); - exit(1); - } - - /* free strdups */ - if (daddr) - free (daddr); - - if (lport) - free (lport); - - if (sport) - free (sport); - - if (s_datasize) - free (s_datasize); - - if (s_loops) - free (s_loops); - - if (s_subloops) - free (s_subloops); - - return; - -out: - fprintf(stderr, "udpclient expects the following format: udpclient:dest_addr:dest_port[:listen_port:datasize:loops:subloops]\n"); - free(udpclient_pas); - exit(255); -} -/*** END UDP CLIENT ***/ diff --git a/ext/picotcp/test/examples/udp_echo.c b/ext/picotcp/test/examples/udp_echo.c deleted file mode 100644 index 2a9ce3c..0000000 --- a/ext/picotcp/test/examples/udp_echo.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "utils.h" -#include -#include -#include - -/**** START UDP ECHO ****/ -/* - * udpecho expects the following format: udpecho:bind_addr:listen_port[:sendto_port:datasize] - * bind_addr: IP address to bind to - * listen_port: port number on which the udpecho listens - * sendto_port [OPTIONAL]: port number to echo datagrams to (echo to originating IP address) - * datasize [OPTIONAL]: max size of the data red from the socket in one go - * - * REMARK: once an optional parameter is given, all optional parameters need a value! - * - * f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.3:255.255.255.0: -a udpecho:10.40.0.3:6667:6667:1400 - */ -static int udpecho_exit = 0; - -struct udpecho_pas *udpecho_pas; - -void cb_udpecho(uint16_t ev, struct pico_socket *s) -{ - char *recvbuf = NULL; - uint16_t port = 0; - int r = 0; - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } peer; - if (udpecho_exit) - return; - - if (ev == PICO_SOCK_EV_RD) { - recvbuf = calloc(1, udpecho_pas->datasize); - if (!recvbuf) { - printf("%s: no memory available\n", __FUNCTION__); - return; - } - - do { - r = pico_socket_recvfrom(s, recvbuf, udpecho_pas->datasize, IPV6_MODE ? (void *)peer.ip6.addr : (void *)&peer.ip4.addr, &port); - /* printf("UDP recvfrom returned %d\n", r); */ - if (r > 0) { - if (strncmp(recvbuf, "end", 3) == 0) { - printf("Client requested to exit... test successful.\n"); - if (!pico_timer_add(1000, deferred_exit, udpecho_pas)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - udpecho_exit++; - } - - pico_socket_sendto(s, recvbuf, r, IPV6_MODE ? (void *)peer.ip6.addr : (void *)&peer.ip4.addr, port); - } - } while (r > 0); - free(recvbuf); - } - - if (ev == PICO_SOCK_EV_ERR) { - printf("Socket Error received. Bailing out.\n"); - free(udpecho_pas); - exit(7); - } - - picoapp_dbg("%s: received packet from %08X:%u\n", __FUNCTION__, long_be(peer), short_be(port)); -} - -void app_udpecho(char *arg) -{ - char *baddr = NULL, *lport = NULL, *sport = NULL, *s_datasize = NULL; - char *nxt = arg; - uint16_t listen_port = 0; - struct pico_ip4 inaddr_bind = { }; - struct pico_ip6 inaddr_bind6 = { }; - int ret = 0; - - udpecho_pas = calloc(1, sizeof(struct udpecho_pas)); - if (!udpecho_pas) { - printf("%s: no memory available\n", __FUNCTION__); - exit(255); - } - - udpecho_pas->s = NULL; - udpecho_pas->sendto_port = 0; - udpecho_pas->datasize = 5000; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&baddr, nxt); - if (baddr) { - if (!IPV6_MODE) - pico_string_to_ipv4(baddr, &inaddr_bind.addr); - - #ifdef PICO_SUPPORT_IPV6 - else - pico_string_to_ipv6(baddr, inaddr_bind6.addr); - #endif - } else { - goto out; - } - } else { - /* missing bind_addr */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&lport, nxt); - if (lport && atoi(lport)) { - listen_port = short_be(atoi(lport)); - } else { - listen_port = short_be(5555); - } - } else { - /* missing listen_port */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&sport, nxt); - if (sport && atoi(sport)) { - udpecho_pas->sendto_port = atoi(sport); - } else { - /* incorrect send_port */ - goto out; - } - } else { - /* missing send_port, use default */ - } - - if (nxt) { - nxt = cpy_arg(&s_datasize, nxt); - if (s_datasize && atoi(s_datasize)) { - udpecho_pas->datasize = atoi(s_datasize); - } else { - /* incorrect datasize */ - goto out; - } - } else { - /* missing datasize, incomplete optional parameters? -> exit */ - if (sport) - goto out; - } - - /* end of argument parsing */ - if (!IPV6_MODE) - udpecho_pas->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpecho); - else - udpecho_pas->s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &cb_udpecho); - - if (!udpecho_pas->s) { - printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); - free(udpecho_pas); - exit(1); - } - - if (!IPV6_MODE) - ret = pico_socket_bind(udpecho_pas->s, &inaddr_bind, &listen_port); - else { - ret = pico_socket_bind(udpecho_pas->s, &inaddr_bind6, &listen_port); - printf("udpecho> Bound to [%s]:%d.\n", baddr, short_be(listen_port)); - } - - if (ret != 0) { - free(udpecho_pas); - if (!IPV6_MODE) - printf("%s: error binding socket to %08X:%u: %s\n", __FUNCTION__, long_be(inaddr_bind.addr), short_be(listen_port), strerror(pico_err)); - else - printf("%s: error binding socket to [%s]:%u: %s\n", __FUNCTION__, baddr, short_be(listen_port), strerror(pico_err)); - - exit(1); - } - -#ifdef PICOAPP_IPFILTER - { - struct pico_ip4 address, in_addr_netmask, in_addr; - /* struct pico_ipv4_link *link; */ - int ret = 0; - address.addr = 0x0800280a; - in_addr_netmask.addr = 0x00FFFFFF; - in_addr.addr = 0x0000320a; - /* link = pico_ipv4_link_get(&address); */ - - printf("udpecho> IPFILTER ENABLED\n"); - - /*Adjust your IPFILTER*/ - ret |= pico_ipv4_filter_add(NULL, 17, NULL, NULL, &in_addr, &in_addr_netmask, 0, 5555, 0, 0, FILTER_DROP); - - if (ret < 0) - printf("Filter_add invalid argument\n"); - } -#endif - - printf("\n%s: UDP echo launched. Receiving packets of %u bytes on port %u\n\n", __FUNCTION__, udpecho_pas->datasize, short_be(listen_port)); - - /* free strdups */ - if (baddr) - free (baddr); - - if (lport) - free (lport); - - if (sport) - free (sport); - - if (s_datasize) - free (s_datasize); - - return; - -out: - fprintf(stderr, "udpecho expects the following format: udpecho:bind_addr:listen_port[:sendto_port:datasize]\n"); - free(udpecho_pas); - exit(255); -} -/*** END UDP ECHO ***/ diff --git a/ext/picotcp/test/examples/udp_sendto_test.c b/ext/picotcp/test/examples/udp_sendto_test.c deleted file mode 100644 index 3d8e520..0000000 --- a/ext/picotcp/test/examples/udp_sendto_test.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "utils.h" -#include -#include - -/**** START UDP ECHO ****/ -/* - * udpecho expects the following format: udpecho:bind_addr:listen_port[:sendto_port:datasize] - * bind_addr: IP address to bind to - * listen_port: port number on which the udpecho listens - * sendto_port [OPTIONAL]: port number to echo datagrams to (echo to originating IP address) - * datasize [OPTIONAL]: max size of the data red from the socket in one go - * - * REMARK: once an optional parameter is given, all optional parameters need a value! - * - * f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.3:255.255.255.0: -a udpecho:10.40.0.3:6667:6667:1400 - */ - -void dummy_cb(uint16_t __attribute__((unused)) ev, struct pico_socket __attribute__((unused)) *s) -{ - -} - -void app_sendto_test(char *arg) -{ - char *nxt = arg; - char *dstaddr = NULL; - char *dstport = NULL; - struct pico_ip4 inaddr_dst = {}; - struct pico_ip6 inaddr_dst6 = {}; - uint16_t dport; - struct pico_socket *sock; - int ret; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&dstaddr, nxt); - if (dstaddr) { - if (!IPV6_MODE) - pico_string_to_ipv4(dstaddr, &inaddr_dst.addr); - - #ifdef PICO_SUPPORT_IPV6 - else - pico_string_to_ipv6(dstaddr, inaddr_dst6.addr); - #endif - } else { - goto out; - } - } else { - /* missing bind_addr */ - goto out; - } - - if (nxt) { - nxt = cpy_arg(&dstport, nxt); - if (dstport && atoi(dstport)) { - dport = short_be(atoi(dstport)); - } else { - dport = short_be(5555); - } - } else { - /* missing listen_port */ - goto out; - } - - if (!IPV6_MODE) - sock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &dummy_cb); - else - sock = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &dummy_cb); - - ret = pico_socket_sendto(sock, "Testing", 7u, ((IPV6_MODE) ? (void *)(&inaddr_dst6) : (void *)(&inaddr_dst)), dport); - if (ret < 0) - printf("Failure in first pico_socket_send\n"); - - ret = pico_socket_sendto(sock, "Testing", 7u, ((IPV6_MODE) ? (void *)(&inaddr_dst6) : (void *)(&inaddr_dst)), dport); - if (ret < 0) - printf("Failure in second pico_socket_send\n"); - - ret = pico_socket_close(sock); - if (ret) - printf("Failure in pico_socket_close\n"); - - printf("\n%s: UDP sendto test launched. Sending packets to ip %s port %u\n\n", __FUNCTION__, dstaddr, short_be(dport)); - return; - -out: - fprintf(stderr, "udp_sendto_test expects the following format: udp_sendto_test:dest_addr:[dest_por]t\n"); - exit(255); -} diff --git a/ext/picotcp/test/examples/udpnat.c b/ext/picotcp/test/examples/udpnat.c deleted file mode 100644 index b8b72f3..0000000 --- a/ext/picotcp/test/examples/udpnat.c +++ /dev/null @@ -1,151 +0,0 @@ -#include "utils.h" -#include -#include - -/*** START UDP NAT CLIENT ***/ -/* ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10: -a udpnatclient:10.50.0.8:6667: */ -static struct pico_ip4 udpnatclient_inaddr_dst; -static uint16_t udpnatclient_port_be; - -void udpnatclient_send(pico_time __attribute__((unused)) now, void *arg) -{ - int i, w; - struct pico_socket *s = (struct pico_socket *)arg; - char buf[1400] = { }; - char end[4] = "end"; - static int loop = 0; - - for ( i = 0; i < 3; i++) { - w = pico_socket_send(s, buf, 1400); - } - if (++loop > 1000) { - udpnatclient_port_be = 0; - for (i = 0; i < 3; i++) { - w = pico_socket_send(s, end, 4); - if (w <= 0) - break; - - printf("End!\n"); - } - if (!pico_timer_add(1000, deferred_exit, NULL)) { - printf("Failed to start exit timer, exiting now\n"); - exit(1); - } - return; - } -} - -void cb_udpnatclient(uint16_t ev, struct pico_socket *s) -{ - char recvbuf[1400]; - int r = 0; - - if (ev & PICO_SOCK_EV_RD) { - do { - r = pico_socket_recv(s, recvbuf, 1400); - } while(r > 0); - } - - if (ev == PICO_SOCK_EV_ERR) { - printf("Socket Error received. Bailing out.\n"); - exit(7); - } - - /* Not closing to test port check */ - /* pico_socket_close(s); */ -} - -void udpnatclient_open_socket(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg) -{ - struct pico_socket *s = NULL; - static int loop; - - if (!udpnatclient_port_be) - return; - - loop++; - picoapp_dbg(">>>>> Loop %d\n", loop); - if (!(loop % 100)) - printf("Created %d sockets\n", loop); - - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpnatclient); - if (!s) - exit(1); - - if (pico_socket_connect(s, &udpnatclient_inaddr_dst, udpnatclient_port_be) != 0) - { - printf("Error connecting\n"); - exit(1); - } - - picoapp_dbg("New socket with port %u\n", s->local_port); - - if (!pico_timer_add(25, udpnatclient_send, s)) { - printf("Failed to start send timer, exiting now\n"); - exit(1); - } - - if (!pico_timer_add(25, udpnatclient_open_socket, 0)) { - printf("Failed to start open_socket timer, exiting now\n"); - exit(1); - } -} - -void app_udpnatclient(char *arg) -{ - struct pico_socket *s; - char *daddr, *dport; - int port = 0; - uint16_t port_be = 0; - struct pico_ip4 inaddr_dst = ZERO_IP4; - char *nxt; - - nxt = cpy_arg(&daddr, arg); - if (!daddr) { - fprintf(stderr, " udpnatclient expects the following format: udpnatclient:dest_addr[:dest_port]\n"); - exit(255); - } - - if (nxt) { - nxt = cpy_arg(&dport, nxt); - if (dport) { - port = atoi(dport); - if (port > 0) - port_be = short_be(port); - } - } - - if (port == 0) { - port_be = short_be(5555); - } - - printf("UDP NAT client started. Sending packets to %s:%d\n", daddr, short_be(port_be)); - - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpnatclient); - if (!s) - exit(1); - - pico_string_to_ipv4(daddr, &inaddr_dst.addr); - - if (pico_socket_connect(s, &inaddr_dst, port_be) != 0) - { - printf("Error binding the port \n"); - exit(1); - } - - picoapp_dbg("New socket with port %u\n", s->local_port); - - udpnatclient_inaddr_dst = inaddr_dst; - udpnatclient_port_be = port_be; - - if (!pico_timer_add(100, udpnatclient_send, s)) { - printf("Failed to start send timer, exiting now\n"); - exit(1); - } - - if (!pico_timer_add(1000, udpnatclient_open_socket, 0)) { - printf("Failed to start open_socket timer, exiting now\n"); - exit(1); - } -} -/*** END UDP NAT CLIENT ***/ diff --git a/ext/picotcp/test/examples/utils.h b/ext/picotcp/test/examples/utils.h deleted file mode 100644 index a606318..0000000 --- a/ext/picotcp/test/examples/utils.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PICO_EXAMPLES_UTILS_H -#define PICO_EXAMPLES_UTILS_H -#include -#define TCPSIZ (1024 * 1024 * 5) -extern struct pico_ip4 ZERO_IP4; -extern struct pico_ip_mreq ZERO_MREQ; -extern struct pico_ip_mreq_source ZERO_MREQ_SRC; -extern struct pico_ip6 ZERO_IP6; -extern struct pico_ip_mreq ZERO_MREQ_IP6; -extern struct pico_ip_mreq_source ZERO_MREQ_SRC_IP6; -#define picoapp_dbg(...) do {} while(0) -/* #define picoapp_dbg printf */ -extern int IPV6_MODE; - - -extern struct pico_ip4 inaddr_any; -extern struct pico_ip6 inaddr6_any; - -extern char *cpy_arg(char **dst, char *str); - -extern void deferred_exit(pico_time now, void *arg); - -struct udpclient_pas { - struct pico_socket *s; - uint8_t loops; - uint8_t subloops; - uint16_t datasize; - uint16_t sport; - union pico_address dst; -}; /* per application struct */ - -struct udpecho_pas { - struct pico_socket *s; - uint16_t sendto_port; /* big-endian */ - uint16_t datasize; -}; /* per application struct */ - - -#endif diff --git a/ext/picotcp/test/mkunits.sh b/ext/picotcp/test/mkunits.sh deleted file mode 100755 index ee51e35..0000000 --- a/ext/picotcp/test/mkunits.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/bash -# By Daniele. -#set -x -filename=$1 -if [ [x$1] == [x] ]; then - echo USAGE: $0 filename.c - exit 4 -fi - -#CMOCK="../CMock/lib/cmock.rb" - -bname=`basename $filename` -cat $filename |grep static|grep \( | grep \) >/tmp/$bname - -if (test -f ./test/unit/modunit_$bname); then - echo The destination file ./test/unit/modunit_$bname already exists. Exiting... - exit 0 -fi - -cat $filename |grep "\#include " > ./test/unit/modunit_$bname -MYSELF=`echo $bname | cut -d"." -f1`.h -INCLUDES=`cat $filename |grep "\#include \"" |grep -v $MYSELF| cut -d '"' -f 2` - -echo includes are: -echo $INCLUDES -echo "#include \"$filename\"" >>./test/unit/modunit_$bname -echo "#include \"check.h\"" >>./test/unit/modunit_$bname -echo >> ./test/unit/modunit_$bname -echo >> ./test/unit/modunit_$bname - -while read fn ; do - fname=`echo $fn | cut -d "(" -f 1| cut -d" " -f 3` - echo "START_TEST(tc_$fname)" >>./test/unit/modunit_$bname - echo "{" >>./test/unit/modunit_$bname - echo " /* TODO: test this: $fn */" >>./test/unit/modunit_$bname - echo "}" >>./test/unit/modunit_$bname - echo "END_TEST" >>./test/unit/modunit_$bname -done > ./test/unit/modunit_$bname -echo >> ./test/unit/modunit_$bname -echo "Suite *pico_suite(void) -{ - Suite *s = suite_create(\"PicoTCP\"); -" >> ./test/unit/modunit_$bname - -while read fn ; do - fname=`echo $fn | cut -d "(" -f 1| cut -d" " -f 3` - echo " TCase *TCase_$fname = tcase_create(\"Unit test for $fname\");" >> ./test/unit/modunit_$bname -done > ./test/unit/modunit_$bname -echo >> ./test/unit/modunit_$bname - -while read fn ; do - fname=`echo $fn | cut -d "(" -f 1| cut -d" " -f 3` - echo " tcase_add_test(TCase_$fname, tc_$fname);" >> ./test/unit/modunit_$bname - echo " suite_add_tcase(s, TCase_$fname);" >> ./test/unit/modunit_$bname -done > ./test/unit/modunit_$bname -echo "}">> ./test/unit/modunit_$bname - -echo " -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -}" >>./test/unit/modunit_$bname - - -echo Gernerated test ./test/unit/modunit_$bname -#echo Generating mocks... -#mkdir -p mocks -# -#CFILES="" -#for i in $INCLUDES; do -# ii=`find -name $i | grep -v build` -# ruby $CMOCK $ii -# CFILE=`basename $ii |cut -d "." -f 1`.c -# CFILES="$CFILES mocks/Mock$CFILE" -#done -ELF=`echo build/test/modunit_$bname | sed -e "s/\.c/.elf/g"` - -echo -echo - -MOCKS=$(gcc -I include/ -I modules/ -I. test/unit/modunit_$bname $CFILES -lcheck -pthread -lm -lrt -o $ELF 2>&1 |grep "undefined reference to" | sed -e "s/.*\`//g" | sed -e "s/'.*$//g" |sort | uniq) - -for m in $MOCKS; do - decl=`grep -R $m * |grep -v ");" | grep -v Binary | cut -d ":" -f 2` - echo $decl >> ./test/unit/modunit_$bname - echo "{" >> ./test/unit/modunit_$bname - echo "/* TODO: MOCK ME! */">> ./test/unit/modunit_$bname - echo "}" >> ./test/unit/modunit_$bname -done -gcc -I include/ -I modules/ -I. test/unit/modunit_$bname $CFILES -lcheck -pthread -lm -lrt -o $ELF && echo "Successfully compiled $ELF" - -#echo " /* TODO: MOCKS NEEDED: $MOCKS */ " >>./test/unit/modunit_$bname diff --git a/ext/picotcp/test/olsr_test.sh b/ext/picotcp/test/olsr_test.sh deleted file mode 100755 index 597b233..0000000 --- a/ext/picotcp/test/olsr_test.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -sudo vde_switch -t pic0 -s /tmp/pic0.ctl -d -sudo vde_switch -s /tmp/pic1.ctl -d -sudo vde_switch -s /tmp/pic2.ctl -d -sudo vde_switch -s /tmp/pic3.ctl -d - -sudo ifconfig pic0 10.40.0.254/16 up - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0: \ - --vde pic1:/tmp/pic1.ctl:10.41.0.9:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic1.ctl:10.41.0.1:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic1.ctl:10.41.0.2:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic1.ctl:10.41.0.3:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic1.ctl:10.41.0.10:255.255.0.0: \ - --vde pic1:/tmp/pic2.ctl:10.42.0.10:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic2.ctl:10.42.0.1:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic2.ctl:10.42.0.2:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic1.ctl:10.42.0.3:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic2.ctl:10.42.0.11:255.255.0.0: \ - --vde pic1:/tmp/pic3.ctl:10.43.0.11:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic3.ctl:10.43.0.1:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic3.ctl:10.43.0.2:255.255.0.0: \ - -a olsr: & - -./build/test/picoapp.elf \ - --vde pic0:/tmp/pic3.ctl:10.43.0.3:255.255.0.0: \ - -a olsr: & - -sleep 5 -sudo killall olsrd -sudo olsrd -i pic0 - diff --git a/ext/picotcp/test/perf.sh b/ext/picotcp/test/perf.sh deleted file mode 100755 index c9debbe..0000000 --- a/ext/picotcp/test/perf.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -THRESHOLD=300 -sh ./test/vde_sock_start_user.sh -sleep 2 - -(iperf -s >/tmp/iperf.log)& -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app iperfc:10.50.0.1: &>/dev/null -killall iperf -RES=`cat /tmp/iperf.log |grep Mbits |sed -e "s/.*Bytes//g" |sed -e "s/^[ ]*//g"` -SPEED=`echo $RES | cut -d " " -f 1` -UNITS=`echo $RES | cut -d " " -f 2` - -if [ ["$UNITS"] != ["Mbits/sec"] ]; then - echo "Wrong test result units: expected Mbits/sec, got $UNITS" - exit 1 -fi - -if (test $SPEED -lt $THRESHOLD); then - echo "Speed too low: expected $THRESHOLD MBits/s, got $SPEED $UNITS" - exit 2 -fi - -echo Test result: $SPEED $UNITS - -rm -f /tmp/iperf.log -exit 0 diff --git a/ext/picotcp/test/pico_faulty.c b/ext/picotcp/test/pico_faulty.c deleted file mode 100644 index c9a4405..0000000 --- a/ext/picotcp/test/pico_faulty.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include "pico_faulty.h" - -/* #warning "COMPILING for MEMORY TESTS!" */ - -uint32_t mm_failure_count = 0; -uint32_t cur_mem, max_mem; - -static int called_atexit = 0; - - -void memory_stats(void) -{ - fprintf(stderr, " ################ MAX MEMORY USED in this test: %u\n", max_mem); - -} - -int pico_set_mm_failure(uint32_t nxt) -{ - if (!called_atexit) { - atexit(memory_stats); - called_atexit++; - } - - mm_failure_count = nxt; - return 0; -} diff --git a/ext/picotcp/test/pico_faulty.h b/ext/picotcp/test/pico_faulty.h deleted file mode 100644 index 45f7956..0000000 --- a/ext/picotcp/test/pico_faulty.h +++ /dev/null @@ -1,134 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved. - See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. - Do not redistribute without a written permission by the Copyright - holders. - *********************************************************************/ - - -/* This is a test implementation, with a faulty memory manager, - * intended to increase test coverage - * Warning: not intended for production! - * - */ - - -#ifndef PICO_SUPPORT_POSIX -#define PICO_SUPPORT_POSIX - -#define PICO_FAULTY - -#define MEM_LIMIT (0) - -#include -#include -#include -#include -#include -#include - -extern uint32_t mm_failure_count; -int pico_set_mm_failure(uint32_t nxt); -extern uint32_t max_mem; -extern uint32_t cur_mem; - -/* - #define TIME_PRESCALE - */ -#define dbg printf - -#define stack_fill_pattern(...) do {} while(0) -#define stack_count_free_words(...) do {} while(0) -#define stack_get_free_words() (0) - -static inline void mem_stat_store(void) -{ - char fname_mod[] = "/tmp/pico-mem-report-%hu.txt"; - char fname[200]; - char buffer[20]; - int fd; - snprintf(fname, 200, fname_mod, getpid()); - fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0660); - if (fd < 0) { - return; - } - - snprintf(buffer, 20, "%d\n", max_mem); - write(fd, buffer, strlen(buffer)); - close(fd); -} - - -static inline void *pico_zalloc(size_t x) -{ - uint32_t *ptr; - if (mm_failure_count > 0) { - if (--mm_failure_count == 0) { - fprintf(stderr, "Malloc failed, for test purposes\n"); - return NULL; - } - } - - ptr = (uint32_t *)calloc(x + sizeof(uint32_t), 1); - *ptr = (uint32_t)x; /* store size of alloc */ - cur_mem += (uint32_t)x; - -#ifndef DISABLE_MM_STATS - if (cur_mem > max_mem) { - max_mem = cur_mem; - if ((MEM_LIMIT > 0) && (max_mem > MEM_LIMIT)) - abort(); - - mem_stat_store(); - } - -#endif - return (void*)(ptr + 1); -} - -static inline void pico_free(void *x) -{ - uint32_t *ptr = (uint32_t*)(((uint8_t *)x) - sizeof(uint32_t)); /* fetch size of the alloc */ - cur_mem -= *ptr; - free(ptr); -} - -/* time prescaler */ -#ifdef TIME_PRESCALE -extern int32_t prescale_time; -#endif - -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 -} - -static inline void PICO_IDLE(void) -{ - usleep(5000); -} - -void memory_stats(void); - -#endif /* PICO_SUPPORT_POSIX */ - diff --git a/ext/picotcp/test/picoapp.c b/ext/picotcp/test/picoapp.c deleted file mode 100644 index 58b6ede..0000000 --- a/ext/picotcp/test/picoapp.c +++ /dev/null @@ -1,757 +0,0 @@ -/* PicoTCP Test application */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils.h" - -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_dev_vde.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_socket.h" -#include "pico_dev_tun.h" -#include "pico_dev_tap.h" -#include "pico_nat.h" -#include "pico_icmp4.h" -#include "pico_icmp6.h" -#include "pico_dns_client.h" -#include "pico_dev_loop.h" -#include "pico_dhcp_client.h" -#include "pico_dhcp_server.h" -#include "pico_ipfilter.h" -#include "pico_olsr.h" -#include "pico_sntp_client.h" -#include "pico_mdns.h" -#include "pico_tftp.h" -#include "pico_dev_radiotest.h" -#include "pico_dev_radio_mgr.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef FAULTY -#include "pico_faulty.h" -#endif - -void app_udpecho(char *args); -void app_tcpecho(char *args); -void app_udpclient(char *args); -void app_tcpclient(char *args); -void app_tcpbench(char *args); -void app_natbox(char *args); -void app_udpdnsclient(char *args); -void app_udpnatclient(char *args); -void app_mcastsend(char *args); -void app_mcastreceive_ipv6(char *args); -void app_mcastsend_ipv6(char *args); -void app_mcastreceive(char *args); -void app_ping(char *args); -void app_dhcp_server(char *args); -void app_dhcp_client(char *args); -void app_dns_sd(char *arg, struct pico_ip4 addr); -void app_mdns(char *arg, struct pico_ip4 addr); -void app_sntp(char *args); -void app_tftp(char *args); -void app_slaacv4(char *args); -void app_udpecho(char *args); -void app_sendto_test(char *args); -void app_noop(void); - -struct pico_ip4 ZERO_IP4 = { - 0 -}; -struct pico_ip_mreq ZERO_MREQ = { - .mcast_group_addr = {{0}}, - .mcast_link_addr = {{0}} -}; -struct pico_ip_mreq_source ZERO_MREQ_SRC = { - .mcast_group_addr.ip4 = {0}, - .mcast_link_addr.ip4 = {0}, - .mcast_source_addr.ip4 = {0} -}; -struct pico_ip6 ZERO_IP6 = { - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } -}; -struct pico_ip_mreq ZERO_MREQ_IP6 = { - .mcast_group_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}, - .mcast_link_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} -}; -struct pico_ip_mreq_source ZERO_MREQ_SRC_IP6 = { - .mcast_group_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}, - .mcast_link_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}, - .mcast_source_addr.ip6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} -}; - -/* #define INFINITE_TCPTEST */ -#define picoapp_dbg(...) do {} while(0) -/* #define picoapp_dbg printf */ - -/* #define PICOAPP_IPFILTER 1 */ - -int IPV6_MODE; - - -struct pico_ip4 inaddr_any = { - 0 -}; -struct pico_ip6 inaddr6_any = {{0}}; - -char *cpy_arg(char **dst, char *str); - -void deferred_exit(pico_time __attribute__((unused)) now, void *arg) -{ - if (arg) { - free(arg); - arg = NULL; - } - - printf("%s: quitting\n", __FUNCTION__); - exit(0); -} - - - -/** From now on, parsing the command line **/ -#define NXT_MAC(x) ++ x[5] - -/* Copy a string until the separator, - terminate it and return the next index, - or NULL if it encounters a EOS */ -char *cpy_arg(char **dst, char *str) -{ - char *p, *nxt = NULL; - char *start = str; - char *end = start + strlen(start); - char sep = ':'; - - if (IPV6_MODE) - sep = ','; - - p = str; - while (p) { - if ((*p == sep) || (*p == '\0')) { - *p = (char)0; - nxt = p + 1; - if ((*nxt == 0) || (nxt >= end)) - nxt = 0; - - printf("dup'ing %s\n", start); - *dst = strdup(start); - break; - } - - p++; - } - return nxt; -} - -static void __wakeup(uint16_t __attribute__((unused)) ev, struct pico_socket __attribute__((unused)) *s) -{ - -} - - -static void usage(char *arg0) -{ - printf("Usage: %s [--vde name:sock:address:netmask[:gateway]] [--vde ...] [--tun name:address:netmask[:gateway]] [--tun ...] [--app name[:args]]\n\n\n", arg0); - printf("\tall arguments can be repeated, e.g. to run on multiple links or applications\n"); - printf("\t* --app arguments must be at the end *\n"); - exit(255); -} - -#define IF_APPNAME(x) if(strcmp(x, name) == 0) - -int main(int argc, char **argv) -{ - unsigned char macaddr[6] = { - 0, 0, 0, 0xa, 0xb, 0x0 - }; - uint16_t *macaddr_low = (uint16_t *) (macaddr + 2); - struct pico_device *dev = NULL; - struct pico_ip4 addr4 = { - 0 - }; - struct pico_ip4 bcastAddr = ZERO_IP4; - - struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"vde", 1, 0, 'v'}, - {"barevde", 1, 0, 'b'}, - {"tun", 1, 0, 't'}, - {"tap", 1, 0, 'T'}, - {"route", 1, 0, 'r'}, - {"app", 1, 0, 'a'}, - {"dns", 1, 0, 'd'}, - {"loop", 0, 0, 'l'}, - {0, 0, 0, 0} - }; - int option_idx = 0; - int c; - char *app = NULL, *p = argv[0]; - /* parse till we find the name of the executable */ - while (p) { - if (*p == '/') - app = p + 1; - else if (*p == '\0') - break; - else - {} /* do nothing */ - - p++; - } - if (strcmp(app, "picoapp6.elf") == 0) - IPV6_MODE = 1; - - *macaddr_low = (uint16_t)(*macaddr_low ^ (uint16_t)((uint16_t)getpid() & (uint16_t)0xFFFFU)); - printf("My macaddr base is: %02x %02x\n", macaddr[2], macaddr[3]); - printf("My macaddr is: %02x %02x %02x %02x %02x %02x\n", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); - -#ifdef PICO_SUPPORT_MM - pico_mem_init(128 * 1024); -#endif - pico_stack_init(); - /* Parse args */ - while(1) { - c = getopt_long(argc, argv, "6:v:b:t:T:a:r:hl", long_options, &option_idx); - if (c < 0) - break; - - switch(c) { - case 'h': - usage(argv[0]); - break; - case 'T': - { - char *nxt, *name = NULL, *addr = NULL, *nm = NULL, *gw = NULL; - struct pico_ip4 ipaddr, netmask, gateway, zero = ZERO_IP4; - do { - nxt = cpy_arg(&name, optarg); - if (!nxt) break; - - nxt = cpy_arg(&addr, nxt); - if (!nxt) break; - - nxt = cpy_arg(&nm, nxt); - if (!nxt) break; - - cpy_arg(&gw, nxt); - } while(0); - if (!nm) { - fprintf(stderr, "Tun: bad configuration...\n"); - exit(1); - } - - dev = pico_tap_create(name); - if (!dev) { - perror("Creating tap"); - exit(1); - } - - pico_string_to_ipv4(addr, &ipaddr.addr); - pico_string_to_ipv4(nm, &netmask.addr); - pico_ipv4_link_add(dev, ipaddr, netmask); - bcastAddr.addr = (ipaddr.addr) | (~netmask.addr); - if (gw && *gw) { - pico_string_to_ipv4(gw, &gateway.addr); - printf("Adding default route via %08x\n", gateway.addr); - pico_ipv4_route_add(zero, zero, gateway, 1, NULL); - } - -#ifdef PICO_SUPPORT_IPV6 - if (IPV6_MODE) { - struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}, gateway6 = {{0}}, zero6 = {{0}}; - pico_string_to_ipv6(addr, ipaddr6.addr); - pico_string_to_ipv6(nm, netmask6.addr); - pico_ipv6_link_add(dev, ipaddr6, netmask6); - if (gw && *gw) { - pico_string_to_ipv6(gw, gateway6.addr); - pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL); - } - - pico_ipv6_dev_routing_enable(dev); - } - -#endif - } - break; - case 't': - { - char *nxt, *name = NULL, *addr = NULL, *nm = NULL, *gw = NULL; - struct pico_ip4 ipaddr, netmask, gateway, zero = ZERO_IP4; - do { - nxt = cpy_arg(&name, optarg); - if (!nxt) break; - - nxt = cpy_arg(&addr, nxt); - if (!nxt) break; - - nxt = cpy_arg(&nm, nxt); - if (!nxt) break; - - cpy_arg(&gw, nxt); - } while(0); - if (!nm) { - fprintf(stderr, "Tun: bad configuration...\n"); - exit(1); - } - - dev = pico_tun_create(name); - if (!dev) { - perror("Creating tun"); - exit(1); - } - - pico_string_to_ipv4(addr, &ipaddr.addr); - pico_string_to_ipv4(nm, &netmask.addr); - pico_ipv4_link_add(dev, ipaddr, netmask); - bcastAddr.addr = (ipaddr.addr) | (~netmask.addr); - if (gw && *gw) { - pico_string_to_ipv4(gw, &gateway.addr); - printf("Adding default route via %08x\n", gateway.addr); - pico_ipv4_route_add(zero, zero, gateway, 1, NULL); - } - -#ifdef PICO_SUPPORT_IPV6 - if (IPV6_MODE) { - struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}, gateway6 = {{0}}, zero6 = {{0}}; - pico_string_to_ipv6(addr, ipaddr6.addr); - pico_string_to_ipv6(nm, netmask6.addr); - pico_ipv6_link_add(dev, ipaddr6, netmask6); - if (gw && *gw) { - pico_string_to_ipv6(gw, gateway6.addr); - pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL); - } - - pico_ipv6_dev_routing_enable(dev); - } - -#endif - } - break; - case 'v': - { - char *nxt, *name = NULL, *sock = NULL, *addr = NULL, *nm = NULL, *gw = NULL, *addr6 = NULL, *nm6 = NULL, *gw6 = NULL, *loss_in = NULL, *loss_out = NULL; - struct pico_ip4 ipaddr, netmask, gateway, zero = ZERO_IP4; - uint32_t i_pc = 0, o_pc = 0; - printf("+++ OPTARG %s\n", optarg); - do { - nxt = cpy_arg(&name, optarg); - if (!nxt) break; - - nxt = cpy_arg(&sock, nxt); - if (!nxt) break; - - if (!IPV6_MODE) { - nxt = cpy_arg(&addr, nxt); - if (!nxt) break; - - nxt = cpy_arg(&nm, nxt); - if (!nxt) break; - - nxt = cpy_arg(&gw, nxt); - if (!nxt) break; - - nxt = cpy_arg(&loss_in, nxt); - if (!nxt) break; - - nxt = cpy_arg(&loss_out, nxt); - if (!nxt) break; - } else { - nxt = cpy_arg(&addr6, nxt); - if (!nxt) break; - - printf("addr6: %s\n", addr6); - - nxt = cpy_arg(&nm6, nxt); - if (!nxt) break; - - nxt = cpy_arg(&gw6, nxt); - if (!nxt) break; - - nxt = cpy_arg(&loss_in, nxt); - if (!nxt) break; - - nxt = cpy_arg(&loss_out, nxt); - if (!nxt) break; - } - } while(0); - if (!nm && !nm6) { - fprintf(stderr, "Vde: bad configuration...\n"); - exit(1); - } - - macaddr[4] ^= (uint8_t)(getpid() >> 8); - macaddr[5] ^= (uint8_t) (getpid() & 0xFF); - dev = pico_vde_create(sock, name, macaddr); - NXT_MAC(macaddr); - if (!dev) { - perror("Creating vde"); - exit(1); - } - - printf("Vde created.\n"); - - if (!IPV6_MODE) { - pico_string_to_ipv4(addr, &ipaddr.addr); - pico_string_to_ipv4(nm, &netmask.addr); - pico_ipv4_link_add(dev, ipaddr, netmask); - addr4 = ipaddr; - bcastAddr.addr = (ipaddr.addr) | (~netmask.addr); - if (gw && *gw) { - pico_string_to_ipv4(gw, &gateway.addr); - pico_ipv4_route_add(zero, zero, gateway, 1, NULL); - } - } - -#ifdef PICO_SUPPORT_IPV6 - if (IPV6_MODE) { - struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}, gateway6 = {{0}}, zero6 = {{0}}; - printf("SETTING UP IPV6 ADDRESS\n"); - pico_string_to_ipv6(addr6, ipaddr6.addr); - pico_string_to_ipv6(nm6, netmask6.addr); - pico_ipv6_link_add(dev, ipaddr6, netmask6); - if (gw6 && *gw6) { - pico_string_to_ipv6(gw6, gateway6.addr); - pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL); - } - - pico_ipv6_dev_routing_enable(dev); - } - -#endif - if (loss_in && (strlen(loss_in) > 0)) { - i_pc = (uint32_t)atoi(loss_in); - } - - if (loss_out && (strlen(loss_out) > 0)) { - o_pc = (uint32_t)atoi(loss_out); - } - - if (i_pc || o_pc) { - printf(" ---------- >Setting vde packet loss %u:%u\n", i_pc, o_pc); - pico_vde_set_packetloss(dev, i_pc, o_pc); - } - - - } - break; - - case '6': - { - char *nxt, *name = NULL, *area0 = NULL, *area1 = NULL, *dump = NULL; - const char pan_addr[] = "2aaa:abcd::0"; - uint8_t n_id, n_area0, n_area1; - struct pico_ip6 pan; - - /* Copy required command line arguments */ - nxt = cpy_arg(&name, optarg); - if (!nxt) - goto check; - nxt = cpy_arg(&area0, nxt); - if (!nxt) - goto check; - nxt = cpy_arg(&area1, nxt); - if (!nxt) - goto check; - - /* Check required arguments */ -check: if (!name || !area0 || !area1) { - fprintf(stderr, "Usage: -6,id,area\n"); - exit(1); - } - - n_id = (uint8_t) atoi(name); - n_area0 = (uint8_t) atoi(area0); - n_area1 = (uint8_t) atoi(area1); - - if (nxt) { - nxt = cpy_arg(&dump, nxt); - } - - printf("%d:%d:%d\n", n_id, n_area0, n_area1); - - if (!n_id) { - printf("Starting radio-network...\n"); - pico_radio_mgr_start(); - } else { - dev = pico_radiotest_create(n_id, n_area0, n_area1, 0, dump); - if (!dev) { - exit(1); - } - - printf("Radiotest created.\n"); - - /* Add a routable link */ - pico_string_to_ipv6(pan_addr, pan.addr); - pico_ipv6_link_add_local(dev, &pan); - - /* Enable routing on first device */ - if (n_id == 1) { - pico_ipv6_dev_routing_enable(dev); - } - } - break; - } - case 'b': - { - char *nxt, *name = NULL, *sock = NULL; - printf("+++ OPTARG %s\n", optarg); - do { - nxt = cpy_arg(&name, optarg); - if (!nxt) break; - - nxt = cpy_arg(&sock, nxt); - } while(0); - if (!sock) { - fprintf(stderr, "Vde: bad configuration...\n"); - exit(1); - } - - macaddr[4] ^= (uint8_t)(getpid() >> 8); - macaddr[5] ^= (uint8_t)(getpid() & 0xFF); - dev = pico_vde_create(sock, name, macaddr); - NXT_MAC(macaddr); - if (!dev) { - if (sock) - free(sock); - - if (name) - free(name); - - perror("Creating vde"); - exit(1); - } - - if (sock) - free(sock); - - if (name) - free(name); - - printf("Vde created.\n"); - } - break; - case 'l': - { - struct pico_ip4 ipaddr, netmask; - - dev = pico_loop_create(); - if (!dev) { - perror("Creating loop"); - exit(1); - } - - pico_string_to_ipv4("127.0.0.1", &ipaddr.addr); - pico_string_to_ipv4("255.0.0.0", &netmask.addr); - pico_ipv4_link_add(dev, ipaddr, netmask); - printf("Loopback created\n"); -#ifdef PICO_SUPPORT_IPV6 - if (IPV6_MODE) { - struct pico_ip6 ipaddr6 = {{0}}, netmask6 = {{0}}; - pico_string_to_ipv6("::1", ipaddr6.addr); - pico_string_to_ipv6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", netmask6.addr); - pico_ipv6_link_add(dev, ipaddr6, netmask6); - } - - pico_ipv6_dev_routing_enable(dev); - -#endif - } - break; - case 'r': - { - char *nxt, *addr, *nm, *gw; - struct pico_ip4 ipaddr, netmask, gateway; - /* XXX adjust for IPv6 */ - addr = NULL, nm = NULL, gw = NULL; - printf("+++ ROUTEOPTARG %s\n", optarg); - do { - nxt = cpy_arg(&addr, optarg); - if (!nxt) break; - - nxt = cpy_arg(&nm, nxt); - if (!nxt) break; - - nxt = cpy_arg(&gw, nxt); - } while(0); - if (!addr || !nm || !gw) { - fprintf(stderr, "--route expects addr:nm:gw:\n"); - usage(argv[0]); - } - - pico_string_to_ipv4(addr, &ipaddr.addr); - pico_string_to_ipv4(nm, &netmask.addr); - pico_string_to_ipv4(gw, &gateway.addr); - if (pico_ipv4_route_add(ipaddr, netmask, gateway, 1, NULL) == 0) - fprintf(stderr, "ROUTE ADDED *** to %s via %s\n", addr, gw); - else - fprintf(stderr, "ROUTE ADD: ERROR %s \n", strerror(pico_err)); - - break; - } - case 'd': - { - /* Add a DNS nameserver IP address */ - char *straddr; - struct pico_ip4 ipaddr; - printf("DNS nameserver address = %s\n", optarg); - cpy_arg(&straddr, optarg); - pico_string_to_ipv4(straddr, &ipaddr.addr); - pico_dns_client_nameserver(&ipaddr, PICO_DNS_NS_ADD); - break; - } - case 'a': - { - char *name = NULL, *args = NULL; - printf("+++ OPTARG %s\n", optarg); - args = cpy_arg(&name, optarg); - - printf("+++ NAME: %s ARGS: %s\n", name, args); - IF_APPNAME("udpecho") { - app_udpecho(args); - } else IF_APPNAME("tcpecho") { - app_tcpecho(args); - } else IF_APPNAME("udpclient") { - app_udpclient(args); - } else IF_APPNAME("tcpclient") { - app_tcpclient(args); - } else IF_APPNAME("tcpbench") { - app_tcpbench(args); - } else IF_APPNAME("natbox") { - app_natbox(args); - } else IF_APPNAME("udpdnsclient") { - app_udpdnsclient(args); - } else IF_APPNAME("udpnatclient") { - app_udpnatclient(args); - } else IF_APPNAME("mcastsend") { -#ifndef PICO_SUPPORT_MCAST - return 0; -#endif - app_mcastsend(args); - } else IF_APPNAME("mcastreceive") { -#ifndef PICO_SUPPORT_MCAST - return 0; -#endif - app_mcastreceive(args); - } - else IF_APPNAME("mcastsend_ipv6") { -#ifndef PICO_SUPPORT_MCAST - return 0; -#endif - app_mcastsend_ipv6(args); - } else IF_APPNAME("mcastreceive_ipv6") { -#ifndef PICO_SUPPORT_MCAST - return 0; -#endif - app_mcastreceive_ipv6(args); - } - -#ifdef PICO_SUPPORT_PING - else IF_APPNAME("ping") { - app_ping(args); - } -#endif - else IF_APPNAME("dhcpserver") { -#ifndef PICO_SUPPORT_DHCPD - return 0; -#else - app_dhcp_server(args); -#endif - } else IF_APPNAME("dhcpclient") { -#ifndef PICO_SUPPORT_DHCPC - return 0; -#else - app_dhcp_client(args); -#endif - } else IF_APPNAME("dns_sd") { -#ifndef PICO_SUPPORT_DNS_SD - return 0; -#else - app_dns_sd(args, addr4); -#endif - } else IF_APPNAME("mdns") { -#ifndef PICO_SUPPORT_MDNS - return 0; -#else - app_mdns(args, addr4); -#endif -#ifdef PICO_SUPPORT_SNTP_CLIENT - } else IF_APPNAME("sntp") { - app_sntp(args); -#endif - } else IF_APPNAME("bcast") { - struct pico_ip4 any = { - .addr = 0xFFFFFFFFu - }; - - struct pico_socket *s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &__wakeup); - pico_socket_sendto(s, "abcd", 5u, &any, 1000); - - pico_socket_sendto(s, "abcd", 5u, &bcastAddr, 1000); -#ifdef PICO_SUPPORT_TFTP - } else IF_APPNAME("tftp") { - app_tftp(args); -#endif - } else IF_APPNAME("noop") { - app_noop(); -#ifdef PICO_SUPPORT_OLSR - } else IF_APPNAME("olsr") { - dev = pico_get_device("pic0"); - if(dev) { - pico_olsr_add(dev); - } - - dev = pico_get_device("pic1"); - if(dev) { - pico_olsr_add(dev); - } - - app_noop(); -#endif - } else IF_APPNAME("slaacv4") { -#ifndef PICO_SUPPORT_SLAACV4 - return 0; -#else - app_slaacv4(args); -#endif - } else IF_APPNAME("udp_sendto_test") { - app_sendto_test(args); - } else { - fprintf(stderr, "Unknown application %s\n", name); - usage(argv[0]); - } - } - break; - } - } - if (!dev) { - printf("nodev"); - usage(argv[0]); - } - -#ifdef FAULTY - atexit(memory_stats); -#endif - printf("%s: launching PicoTCP loop\n", __FUNCTION__); - while(1) { - pico_stack_tick(); - usleep(2000); - } -} diff --git a/ext/picotcp/test/ppp.c b/ext/picotcp/test/ppp.c deleted file mode 100644 index 5a95b3c..0000000 --- a/ext/picotcp/test/ppp.c +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef PICO_SUPPORT_POLARSSL -#include -#endif -#ifdef PICO_SUPPORT_CYASSL -#include -#endif -#define MODEM "/dev/ttyUSB0" -#define SPEED 236800 -/* #define APN "gprs.base.be" */ -#define APN "web.be" -#define PASSWD "web" -#define USERNAME "altran" -/* #define DEBUG_FLOW */ -static int fd = -1; -static int idx; -static int ping_on = 0; -static struct pico_device *ppp = NULL; - -static void sigusr1_hdl(int signo) -{ - fprintf(stderr, "SIGUSR1: Connecting!\n"); - if (ppp) - pico_ppp_connect(ppp); -} - -static void sigusr2_hdl(int signo) -{ - fprintf(stderr, "SIGUSR2/SIGINT: Disconnecting!\n"); - if (ppp) - pico_ppp_disconnect(ppp); - - if (signo == SIGINT) - exit(0); -} - -#ifdef PICO_SUPPORT_POLARSSL -static void md5sum(uint8_t *dst, const uint8_t *src, size_t len) -{ - md5(src, len, dst); -} -#endif - -#ifdef PICO_SUPPORT_CYASSL -static void md5sum(uint8_t *dst, const uint8_t *src, size_t len) -{ - Md5 md5; - InitMd5(&md5); - Md5Update(&md5, src, len); - Md5Final(&md5, dst); -} -#endif - -int modem_read(struct pico_device *dev, void *data, int len) -{ - int r; - r = read(fd, data, len); -#ifdef DEBUG_FLOW - if (r > 0) { - printf(" <<< "); - for(idx = 0; idx < r; idx++) { - printf(" %02x", ((uint8_t*)data)[idx]); - } - printf("\n"); - } - -#endif - - return r; -} - -int modem_write(struct pico_device *dev, const void *data, int len) -{ - int r; -#ifdef DEBUG_FLOW - printf(" >>> "); - for(idx = 0; idx < len; idx++) { - printf(" %02x", ((uint8_t*)data)[idx]); - } - printf("\n"); -#endif - r = write(fd, data, len); - return r; -} - -int modem_set_speed(struct pico_device *dev, uint32_t speed) -{ - struct termios term; - if (tcgetattr(fd, &term) != 0) - return 6; - - if (cfsetspeed(&term, B115200) != 0) - return 7; - - if (tcsetattr(fd, TCSANOW, &term) != 0) - return 8; - - printf("Speed set to 115200.\n"); - return 0; -} - -void cb_ping(struct pico_icmp4_stats *s) -{ - char host[30]; - pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("%lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", s->size, host, s->seq, s->time); - } else { - dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err); - } -} - -static void cb_sock(uint16_t ev, struct pico_socket *s) -{ - -} - -static void ping(void) -{ - struct pico_socket *s; - struct pico_ip4 dst; - - pico_string_to_ipv4("80.68.95.85", &dst.addr); - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, cb_sock); - pico_socket_connect(s, &dst, short_be(80)); - pico_icmp4_ping("80.68.95.85", 10, 1000, 4000, 8, cb_ping); -} - - -int main(int argc, const char *argv[]) -{ - const char *path = MODEM; - const char *apn = APN; - const char *passwd = PASSWD; - const char *username = USERNAME; - - if (argc > 1) - path = argv[1]; - - if (argc > 2) - apn = argv[2]; - - if (argc > 3) - passwd = argv[3]; - - fd = open(path, O_RDWR); - if (fd < 0) - return 1; - - fcntl(fd, F_SETFL, O_NONBLOCK); - - signal(SIGUSR1, sigusr1_hdl); - signal(SIGUSR2, sigusr2_hdl); - signal(SIGINT, sigusr2_hdl); - - pico_stack_init(); - -#if defined PICO_SUPPORT_POLARSSL || defined PICO_SUPPORT_CYASSL - pico_register_md5sum(md5sum); -#endif - - ppp = pico_ppp_create(); - if (!ppp) - return 2; - - pico_ppp_set_serial_read(ppp, modem_read); - pico_ppp_set_serial_write(ppp, modem_write); - pico_ppp_set_serial_set_speed(ppp, modem_set_speed); - - pico_ppp_set_apn(ppp, apn); - pico_ppp_set_password(ppp, passwd); - pico_ppp_set_username(ppp, username); - - pico_ppp_connect(ppp); - - while(1 < 2) { - pico_stack_tick(); - usleep(1000); - if (ppp->link_state(ppp) && !ping_on) { - ping_on++; - ping(); - } - } -} diff --git a/ext/picotcp/test/python/dhcp.py b/ext/picotcp/test/python/dhcp.py deleted file mode 100755 index 3891914..0000000 --- a/ext/picotcp/test/python/dhcp.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python -# dhcp.py -# Butterfly-like topology test for dhcp -# One DHCP server, serving on two interface -# Eigth DHCP clients, four on each network -# -# s1----@ @----r1 -# s2-----\__ DHCP __/-----r2 -# s3-----/ \-----r3 -# s4----@ @----r4 -# - - -from topology import * - -T = Topology() -net1 = Network(T, "pyt1") -net2 = Network(T, "pyt2") - -server = Host(T, net1, net2, args="dhcpserver:eth1:172.16.1.2:255.255.255.0:64:128:eth2:172.16.2.2:255.255.255.0:64:128") - -s1 = Host(T, net1, args="dhcpclient:eth1") -s2 = Host(T, net1, args="dhcpclient:eth1") -s3 = Host(T, net1, args="dhcpclient:eth1") -s4 = Host(T, net1, args="dhcpclient:eth1") -r1 = Host(T, net2, args="dhcpclient:eth1") -r2 = Host(T, net2, args="dhcpclient:eth1") -r3 = Host(T, net2, args="dhcpclient:eth1") -r4 = Host(T, net2, args="dhcpclient:eth1") - -raw_input("Press enter to continue ...") -start(T) - -wait(server) - -cleanup() diff --git a/ext/picotcp/test/python/fairness.py b/ext/picotcp/test/python/fairness.py deleted file mode 100755 index d78b85e..0000000 --- a/ext/picotcp/test/python/fairness.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/python -# fairness.py -# A complex test for butterly-like topology, -# using 3 TCP connections and 3 ping flows. -# -# s1---. .---r1 -# s2----\ / -# s3-----\__.R1---R2.__/__.--r2 -# s4-----/ \ -# s5----/ \_.--r3 -# s6---^ -# - -from topology import * - -T = Topology() -net1 = Network(T) -net2 = Network(T) -net3 = Network(T) - -#router1 = Host(T, net1, net2, "natbox:172.16.2.1:") -#router2 = Host(T, net2, net3, "natbox:172.16.3.1:") -router1 = Host(T, net1, net2) -router2 = Host(T, net2, net3) - -send1 = Host(T, net1, args="tcpbench:t:172.16.3.2:") -send2 = Host(T, net1, args="tcpbench:t:172.16.3.3:") -send3 = Host(T, net1, args="tcpbench:t:172.16.3.4:") - -send4 = Host(T, net1, args="ping:172.16.3.2:") -send5 = Host(T, net1, args="ping:172.16.3.3:") -send6 = Host(T, net1, args="ping:172.16.3.4:") - - -recv1 = Host(T, net3, args="tcpbench:r:") -recv2 = Host(T, net3, args="tcpbench:r:") -recv3 = Host(T, net3, args="tcpbench:r:") -recv4 = Host(T, net3, args="tcpbench:r:") - - -sleep(1) -start(T) - -wait(send1) -wait(send2) -wait(send3) - -cleanup() diff --git a/ext/picotcp/test/python/fairness_bottleneck.py b/ext/picotcp/test/python/fairness_bottleneck.py deleted file mode 100755 index a88cb32..0000000 --- a/ext/picotcp/test/python/fairness_bottleneck.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python -# fairness.py -# A complex test for butterly-like topology, -# using 3 TCP connections and 3 ping flows. -# -# Bottleneck of 4 Mbit/300 ms overall delay is added. -# -# s1---. .---r1 -# s2----\ / -# s3-----\__.R1---R2.__/__.--r2 -# s4-----/ \ -# s5----/ \_.--r3 -# s6---^ -# - -from topology import * - -T = Topology() -net1 = Network(T) -net2 = Network(T) -net3 = Network(T) - -router1 = Host(T, net1, net2, delay2="150", bw2="20M") -router2 = Host(T, net2, net3) - -send1 = Host(T, net1, args="tcpbench:t:172.16.3.2:") -send2 = Host(T, net1, args="tcpbench:t:172.16.3.3:") -send3 = Host(T, net1, args="tcpbench:t:172.16.3.4:") - -send4 = Host(T, net1, args="ping:172.16.3.2:") -send5 = Host(T, net1, args="ping:172.16.3.3:") -send6 = Host(T, net1, args="ping:172.16.3.4:") - - -recv1 = Host(T, net3, args="tcpbench:r:") -recv2 = Host(T, net3, args="tcpbench:r:") -recv3 = Host(T, net3, args="tcpbench:r:") - - -sleep(1) -start(T) - -wait(send1) -wait(send2) -wait(send3) - -cleanup() diff --git a/ext/picotcp/test/python/fairness_bottleneck_linux.py b/ext/picotcp/test/python/fairness_bottleneck_linux.py deleted file mode 100755 index 3da270f..0000000 --- a/ext/picotcp/test/python/fairness_bottleneck_linux.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python -# fairness.py -# A complex test for butterly-like topology, -# using 3 TCP connections and 3 ping flows. -# -# Bottleneck of 4 Mbit/300 ms overall delay is added. -# -# s1---. .---r1 -# s2----\ / -# s3-----\__.R1---R2.__/__.--r2 -# s4-----/ \ -# s5----/ \_.--r3 -# s6---^ -# - -from topology import * - -T = Topology() -net1 = Network(T) -net2 = Network(T, "pyt0") -net3 = Network(T) - -router1 = Host(T, net1, net2, delay2="150", bw2="4M") -router2 = Host(T, net2, net3) - -send1 = Host(T, net1, args="tcpbench:t:172.16.3.2:") -send2 = Host(T, net1, args="tcpbench:t:172.16.3.3:") -send3 = Host(T, net1, args="tcpbench:t:172.16.3.4:") - -send4 = Host(T, net1, args="ping:172.16.3.2:") -send5 = Host(T, net1, args="ping:172.16.3.3:") -send6 = Host(T, net1, args="ping:172.16.3.4:") - - -recv1 = Host(T, net3, args="tcpbench:r:") -recv2 = Host(T, net3, args="tcpbench:r:") -recv3 = Host(T, net3, args="tcpbench:r:") - - -sleep(1) -start(T) - -wait(send1) -wait(send2) -wait(send3) - -cleanup() diff --git a/ext/picotcp/test/python/fragmentation.py b/ext/picotcp/test/python/fragmentation.py deleted file mode 100755 index 72a5929..0000000 --- a/ext/picotcp/test/python/fragmentation.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/python -# -# fragmentation.py -# -# Fragmentation test with PicoTCP sending and Linux receiving -# -# (sender) (Receiver) -# PicoTCP ------------------------ Linux -# -# An udpclient is started which will give DATASIZE bytes in one go -# to the socket. This data will be fragmented and send over to the -# Linux, where it is reassembled and received in one piece. -# - -from topology import * -import socket, random, string - -SRC_ADDR = '' -DST_ADDR = '172.16.1.1' -SRC_PORT = 6667 -SENDTO_PORT = 6667 -LISTEN_PORT = 6667 -DATASIZE = 4000 -LOOPS = 4 -SUBLOOPS = 1 -UDPCLIENT = "udpclient:" + str(DST_ADDR) + ":" + str(SENDTO_PORT) + ":" + str(LISTEN_PORT) + ":" + str(DATASIZE) + ":" + str(LOOPS) + ":" + str(SUBLOOPS) - -print UDPCLIENT - -T = Topology() -net1 = Network(T, "pyt0") -h1 = Host(T, net1, args=UDPCLIENT) - -s_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s_udp.bind((SRC_ADDR, SRC_PORT)) -s_udp.settimeout(5); - -raw_input("Press enter to continue ...") -start(T) - -while True: - data, addr = s_udp.recvfrom(DATASIZE) - #print data - if len(data) == DATASIZE: - print '\n\n' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '+++++ fragmentation test IS successful +++++' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '\n\n' - cleanup() - exit(0) - -print '\n\n' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '+++++ fragmentation test NOT successful ++++' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '\n\n' -cleanup() -exit(1) - diff --git a/ext/picotcp/test/python/howto.py b/ext/picotcp/test/python/howto.py deleted file mode 100644 index 7499886..0000000 --- a/ext/picotcp/test/python/howto.py +++ /dev/null @@ -1,135 +0,0 @@ -#PicoTCP topology test environment. -#Guidelines to prepare test scenarios. -# -#The interface is simple, it has three objects: -# * Topology -# * Network -# * Host -# -#And a handful of helping routines, such as: -# * start() -# * loop() -# * sleep() -# * wait() -# -# -######################################################################## -#== Create a test scenario ==# -######################################################################## -# Every script file will start with: "#!/usr/bin/python" in the first -# line, and will have execution permissions. This script is an exception -# because it is not intended to be run, as it is in fact a walkthrough to -# all the functionalities. - -# Importing the topology objects is mandatory, so add: -from topology import * - -# A Topology must be created to use all other objects: -T = Topology() - -# Now, we can create "Network" objects. The networks will have address -# 172.16.X.0/24, where 'X' is the order of creation, starting from 1. -# - -network1 = Network(T) -network2 = Network(T) -# The two networks are separated and using different address pools: -# -# ## ### ## ## ## ### ## ## -# # network1 # # network2 # -# # 172.16.1.0 # # 172.16.2.0 # -# ## ## ###### ## ## ###### -# - -# If you are running your test as root, you can also add a tun-tap connection -# to the network, which will be automatically configured: -networkLocal = Network(T,'tap0') - - -# In the same way ad networks, you can create a PicoTCP Host that connects to a -# network as follows: -host1_1 = Host(T, network1) - -# Also, you can specify a role for the application/host, by using picoapp's -# args format for '--app'. For example, the machine below will ping the previously -# created one: -host1_2 = Host(T, network1, args ="ping:172.16.1.1:") -# -# ## ### ## ## ## ### ## ## -# host1.1--# network1 # # network2 # -# # 172.16.1.0 # # 172.16.2.0 # -# ## ## ###### ## ## ###### -# / -# host1.2___/ -# (ping host1.1) -# - -# At this point, a picoTCP host with two network cards can connect -# the two networks like this: -router1 = Host(T, network1, network2) -# -# ## ### ## ## router1 ## ### ## ## -# host1.1--# network1 #__/ \__ # network2 # -# # 172.16.1.0 # # 172.16.2.0 # -# ## ## ###### ## ## ###### -# / -# host1.2___/ -# (ping host1.1) - -# Now, we can attach an host to the second network too: -# Connection to the host can be an emulated channel, i.e. -# it is possible to add bidirectional delay and limited -# bandwidth in the link between the host and the network: -# - -host2_2 = Host(network2, delay1="100", bw1="500K") -# -# ## ### ## ## router1 ## ### ## ## -# host1.1--# network1 #__/ \__ # network2 # -# # 172.16.1.0 # # 172.16.2.0 # -# ## ## ###### ## ## ###### -# / * -# host1.2.__/ \._*_*_host2.2 -# (ping host1.1) - -## Since the routes will be automatically added before the test starts, -# all the hosts in the networks will be reachable to each other: -# all the picoapps will have their static routes populated automatically -# by the topology tool, no matter how complex the network is. The only -# requirement is that all the networks share at least one router. -# -# For this reason, we can create a host that pings across the network: -host1_4 = Host(T, network1, args="ping:172.16.2.2:") -# -# host1.4. -# (ping 2.2) \ -# \## ### ## ## router1 ## ### ## ## -# host1.1--# network1 #__/ \__ # network2 # -# # 172.16.1.0 # # 172.16.2.0 # -# ## ## ###### ## ## ###### -# / * -# host1.2.__/ \._*_*_host2.2 -# (ping host1.1) - -######################################################################## -#== Start the test ==# -######################################################################## -# All the host will be connected and activated when you call: -start() - -# At this point you may want to define your exit strategy. Valid commands -# are: - -loop() # Loop forever, until the test is interrupted (e.g. by ctrl+c) - -sleep(N) # Sleep N seconds - -wait(host1_4) # Wait for application running on host 1.4, and return only if - # it has terminated - - -######################################################################## -#== End the test ==# -######################################################################## -# Always call: -cleanup() diff --git a/ext/picotcp/test/python/http_server_linux.py b/ext/picotcp/test/python/http_server_linux.py deleted file mode 100755 index 8f72845..0000000 --- a/ext/picotcp/test/python/http_server_linux.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") - -h2 = Host(T, net1, args="httpd") - -sleep(1) -start(T) - -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/multicast_recv.py b/ext/picotcp/test/python/multicast_recv.py deleted file mode 100755 index 534dc32..0000000 --- a/ext/picotcp/test/python/multicast_recv.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/python -# multicast_recv.py -# -# Multicast test with PicoTCP receiving and Linux sending -# -# (sender) (Receiver) -# Linux ------------------------ PicoTCP -# mcast to 224.7.7.7 -# -from topology import * -import socket, random, string - -IF_ADDR = '172.16.1.1' -LINK_ADDR = '172.16.1.2' -MCAST_ADDR = '224.7.7.7' -SRC_PORT = 5555 -LISTEN_PORT = 6667 -SENDTO_PORT = 6667 -MCASTRECV = "mcastreceive:" + str(LINK_ADDR) + ":" + str(MCAST_ADDR) + ":" + str(LISTEN_PORT) + ":" + str(SENDTO_PORT) - -print MCASTRECV - -T = Topology() -net1 = Network(T, "pyt0") -h1 = Host(T, net1, args=MCASTRECV) - -# sending socket -s_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s_udp.bind((IF_ADDR, SRC_PORT)) -s_udp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -s_udp.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) -s_udp.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(str(IF_ADDR))) - -# receiving socket -s_udp_recv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s_udp_recv.bind((IF_ADDR, LISTEN_PORT)) -s_udp_recv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -s_udp_recv.settimeout(5); - -raw_input("Press enter to continue ...") -start(T) -sleep(1) - -while True: - s_udp.sendto("multicast test succeeded", (str(MCAST_ADDR), LISTEN_PORT)) - data = s_udp_recv.recv(4096) - #print data - if 'succeeded' in data: - print '\n\n' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '+++++ multicast_recv test IS successful +++++' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '\n\n' - cleanup() - exit(0) - -print '\n\n' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '+++++ multicast_recv test NOT successful ++++' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '\n\n' -cleanup() -exit(1) - diff --git a/ext/picotcp/test/python/multicast_send.py b/ext/picotcp/test/python/multicast_send.py deleted file mode 100755 index 76ec581..0000000 --- a/ext/picotcp/test/python/multicast_send.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/python -# -# multicast_send.py -# -# Multicast test with PicoTCP sending and Linux receiving -# -# (sender) (Receiver) -# PicoTCP ------------------------ Linux -# mcast to 224.7.7.7 -# - -from topology import * -import socket, random, string, struct - -IF_ADDR = '172.16.1.1' -LINK_ADDR = '172.16.1.2' -MCAST_ADDR = '224.7.7.7' -LISTEN_PORT = 6667 -SENDTO_PORT = 6667 -MCASTSEND = "mcastsend:" + str(LINK_ADDR) + ":" + str(MCAST_ADDR) + ":" + str(SENDTO_PORT) + ":" + str(LISTEN_PORT) - -print MCASTSEND - -T = Topology() -net1 = Network(T, "pyt0") -h1 = Host(T, net1, args=MCASTSEND) - -s_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s_udp.bind((MCAST_ADDR, LISTEN_PORT)) -s_udp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -s_udp.settimeout(5); - -mreq = struct.pack("=4s4s", socket.inet_aton(str(MCAST_ADDR)), socket.inet_aton(str(IF_ADDR))) -s_udp.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) - -raw_input("Press enter to continue ...") -start(T) -sleep(1) - -while True: - data = s_udp.recv(4096) - #print data - if 'end' in data: - print '\n\n' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '+++++ multicast_send test IS successful +++++' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '\n\n' - cleanup() - exit(0) - -print '\n\n' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '+++++ multicast_send test NOT successful ++++' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '\n\n' -cleanup() -exit(1) diff --git a/ext/picotcp/test/python/noop.py b/ext/picotcp/test/python/noop.py deleted file mode 100755 index 9d4d456..0000000 --- a/ext/picotcp/test/python/noop.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") - -#h1 = Host(T, net1) -h2 = Host(T, net1, args="noop") - -sleep(1) -start(T) - -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/ping.py b/ext/picotcp/test/python/ping.py deleted file mode 100755 index a7283ce..0000000 --- a/ext/picotcp/test/python/ping.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T) - -h1 = Host(T, net1) -h2 = Host(T, net1, args="ping:172.16.1.1:") - -sleep(1) -start(T) - -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/ping_delay.py b/ext/picotcp/test/python/ping_delay.py deleted file mode 100755 index 7aa7d7f..0000000 --- a/ext/picotcp/test/python/ping_delay.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T) - -h1 = Host(T, net1, delay1="200") -h2 = Host(T, net1, args="ping:172.16.1.1:") - -sleep(1) -start(T) - -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/ping_linux.py b/ext/picotcp/test/python/ping_linux.py deleted file mode 100755 index b79158e..0000000 --- a/ext/picotcp/test/python/ping_linux.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") - -#h1 = Host(T, net1) -h2 = Host(T, net1, args="ping:172.16.1.1:") - -sleep(1) -start(T) - -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/ping_nat.py b/ext/picotcp/test/python/ping_nat.py deleted file mode 100755 index 336ce8f..0000000 --- a/ext/picotcp/test/python/ping_nat.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, 'nat0') -net2 = Network(T) - - -h1 = Host(T, net1, args="ping:172.16.2.1:") -h2 = Host(T, net2) -router1 = Host(T, net1, net2, args="natbox:172.16.2.2:") - -sleep(1) -start(T) - -wait(h1) -cleanup() diff --git a/ext/picotcp/test/python/reassembly.py b/ext/picotcp/test/python/reassembly.py deleted file mode 100755 index 82a4f27..0000000 --- a/ext/picotcp/test/python/reassembly.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/python -# -# reassemby.py -# -# Reassemly test with PicoTCP receiving and Linux sending -# -# (receiver) (Sender) -# PicoTCP ------------------------ Linux -# -# An udpecho is started which will receive DATASIZE bytes in one go -# from the socket. The Linux will send DATASIZE bytes in one go to the -# udpecho, this data will be sent fragmented. The udpecho is to reassemble -# this data and echo it back. -# - -from topology import * -import socket, random, string - -SRC_ADDR = '' -LINK_ADDR = '172.16.1.2' -SRC_PORT = 5555 -LISTEN_PORT = 6667 -SENDTO_PORT = 5555 -DATASIZE = 3400 -UDPECHO = "udpecho:" + str(LINK_ADDR) + ":" + str(LISTEN_PORT) + ":" + str(SENDTO_PORT) + ":" + str(DATASIZE) - -print UDPECHO - -T = Topology() -net1 = Network(T, "pyt0") -h1 = Host(T, net1, args=UDPECHO) - -str_send = ''.join(random.choice(string.ascii_lowercase) for x in range(DATASIZE)) -#print str_send -s_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s_udp.bind((SRC_ADDR, SRC_PORT)) -s_udp.settimeout(5); - -raw_input("Press enter to continue ...") -start(T) - -while True: - s_udp.sendto(str_send, (LINK_ADDR, LISTEN_PORT)) - data = s_udp.recv(DATASIZE) - #print len(data) - if len(data) == DATASIZE: - print '\n\n' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '+++++ reassembly test IS successful +++++' - print '+++++++++++++++++++++++++++++++++++++++++++++' - print '\n\n' - cleanup() - exit(0) - -print '\n\n' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '+++++ reassembly test NOT successful ++++' -print '+++++++++++++++++++++++++++++++++++++++++++++' -print '\n\n' -cleanup() -exit(1) - diff --git a/ext/picotcp/test/python/tcpbench-delay.py b/ext/picotcp/test/python/tcpbench-delay.py deleted file mode 100755 index cf46681..0000000 --- a/ext/picotcp/test/python/tcpbench-delay.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/python -# - -from topology import * - -T = Topology() -net1 = Network(T, "vde0") - -send1 = Host(T, net1, args="tcpbench:t:172.16.1.3:7770:") -recv1 = Host(T, net1, args="tcpbench:r:7770:", delay1="30", loss1="1") - - -sleep(1) -raw_input("Press enter to continue ...") - -start(T) -wait(send1) -cleanup() diff --git a/ext/picotcp/test/python/tcpbench-tap.py b/ext/picotcp/test/python/tcpbench-tap.py deleted file mode 100755 index 6e30dae..0000000 --- a/ext/picotcp/test/python/tcpbench-tap.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/python -# - -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") -send1 = Host(T, net1, args="tcpbench:t:172.16.1.3:7770:") -recv1 = Host(T, net1, args="tcpbench:r:7770:") - - -sleep(1) -raw_input("Press enter to continue ...") - -start(T) -wait(send1) -cleanup() diff --git a/ext/picotcp/test/python/tcpbench.py b/ext/picotcp/test/python/tcpbench.py deleted file mode 100755 index 58e4768..0000000 --- a/ext/picotcp/test/python/tcpbench.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/python -# - -from topology import * - -T = Topology() -net1 = Network(T) -send1 = Host(T, net1, args="tcpbench:t:172.16.1.2:7770:") -recv1 = Host(T, net1, args="tcpbench:r:7770:") - - -sleep(1) -#raw_input("Press enter to continue ...") - -start(T) -wait(send1) -cleanup() diff --git a/ext/picotcp/test/python/tcpbench_rx_linux.py b/ext/picotcp/test/python/tcpbench_rx_linux.py deleted file mode 100755 index d4fa02e..0000000 --- a/ext/picotcp/test/python/tcpbench_rx_linux.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") - -h2 = Host(T, net1, args="tcpbench:r:6660:") - -sleep(1) -raw_input("Press enter to continue ...") -start(T) - -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/tcpbench_tx_linux.py b/ext/picotcp/test/python/tcpbench_tx_linux.py deleted file mode 100755 index 3bee3d7..0000000 --- a/ext/picotcp/test/python/tcpbench_tx_linux.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") - -#h1 = Host(T, net1) -h3 = Host(T, net1, args="tcpbench:t:172.16.1.1:6660:") - -sleep(1) -raw_input("Press enter to continue ...") -start(T) - -wait(h3) -cleanup() diff --git a/ext/picotcp/test/python/tcpecho_linux.py b/ext/picotcp/test/python/tcpecho_linux.py deleted file mode 100755 index 39065be..0000000 --- a/ext/picotcp/test/python/tcpecho_linux.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -from topology import * - -T = Topology() -net1 = Network(T, "pyt0") - -#h1 = Host(T, net1) -h2 = Host(T, net1, args="tcpecho:8888", delay1="20", loss1="0.01") -#h3 = Host(T, net1, args="tcpbench:t:172.16.1.1:") - -sleep(1) -start(T) - -#wait(h3) -wait(h2) -cleanup() diff --git a/ext/picotcp/test/python/topology.py b/ext/picotcp/test/python/topology.py deleted file mode 100755 index a9df735..0000000 --- a/ext/picotcp/test/python/topology.py +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/python -# Python classes definition for the picoTCP -# topology test environment -# -# Copyright (c) 2013-2017 Altran Intelligent Systems. See LICENSE for usage. - -import sys, os, subprocess, time, re - -def test_tuntap(): - if not os.geteuid()==0: - sys.exit("\nOnly root can use real devices contained in this script\n") - -class Topology: - def __init__(self): - self.nets = [] - self.nodes = [] - self.nextn = 1 - self.hosts = [] - - -class Network: - def __init__(self, topology, real=''): - self.n = topology.nextn - topology.nextn += 1 - self.nodes = [] - self.topology = topology - self.topology.nets.append(self) - self.sock = "/tmp/topology/net"+`self.n` - self.nextn = 1 - vdecmd = ["vde_switch", "-x" , "-s", self.sock, "-m", self.sock+".mgmt"] - if real != '': - test_tuntap() - vdecmd.append('-t') - vdecmd.append(real) - vdecmd.append('-x') - self.pop = subprocess.Popen(vdecmd, stdin=subprocess.PIPE) - self.hosts = [] - print "" - print vdecmd - print "Created network "+self.sock - if real != '': - subprocess.call(["ifconfig",real,"172.16."+`self.n`+".1", "netmask", "255.255.255.0", "up"]) - self.nextn = 2 - -class Node: - def __init__(self,topology, network = None): - if (network is None): - network = Network(topology) - self.net = network - self.n = network.nextn - network.nextn += 1 - self.net.nodes.append(self) - self.topology = topology - self.topology.nodes.append(self) - -class Host: - def add_routes(self, topology): - for eth in [self.eth1, self.eth2]: - if eth and not self.args.startswith("dhcpclient"): - net = eth.net - for h in topology.hosts: - if h.eth1 and h.eth2: - dst="" - gw="" - routing=False - if (h.eth2.net.n == net.n) and (self not in h.eth1.net.hosts): - if h.eth1.net.n > net.n or h.nat == False: - print "FOUND route to net "+`h.eth1.net.n` - dst_net = h.eth1.net.n - gw_net = h.eth2.net.n - gw_n = h.eth2.n - routing=True - elif (h.eth1.net.n == net.n) and (self not in h.eth2.net.hosts): - if h.eth2.net.n > net.n or h.nat == False: - print "FOUND route to net "+`h.eth2.net.n` - dst_net = h.eth2.net.n - gw_net = h.eth1.net.n - gw_n = h.eth1.n - routing=True - - if (routing): - dst = "172.16."+`dst_net`+".0" - gw = "172.16."+`gw_net`+"."+`gw_n` - self.routes.append("-r") - self.routes.append(dst+":255.255.255.0:"+gw+":") - if (routing and gw_net > dst_net and h.nat == False): - dst_net -= 1 - while(dst_net > 0): - dst = "172.16."+`dst_net`+".0" - self.routes.append("-r") - self.routes.append(dst+":255.255.255.0:"+gw+":") - dst_net -= 1 - elif (routing and gw_net != None and gw_net < dst_net): - dst_net += 1 - while(dst_net < net.topology.nextn): - dst = "172.16."+`dst_net`+".0" - self.routes.append("-r") - self.routes.append(dst+":255.255.255.0:"+gw+":") - dst_net += 1 - def parse_options(self, eth, delay, bw, loss): - if (delay != "" or bw != ""): - mysock = eth.net.sock + "__" + `eth.n` - wirecmd = ['wirefilter', '-v'] - wirecmd.append(mysock +":" + eth.net.sock) - if (delay != ''): - wirecmd.append("-d") - wirecmd.append(delay) - if (bw != ''): - wirecmd.append("-b") - wirecmd.append(bw) - if (loss != ''): - wirecmd.append("-l") - wirecmd.append(loss) - print wirecmd - subprocess.Popen(['vde_switch', '-s', mysock], stdin=subprocess.PIPE) - subprocess.Popen(wirecmd, stdin=subprocess.PIPE) - else: - mysock = eth.net.sock - return mysock - - def __init__(self, topology, net1=None, net2=None, gw=None, args="tcpecho:5555", delay1="", bw1="", delay2="", bw2="", loss1="", loss2=""): - if net1: - self.eth1 = Node(topology, net1) - net1.hosts.append(self) - else: - self.eth1 = None - if net2: - self.eth2 = Node(topology, net2) - net2.hosts.append(self) - else: - self.eth2 = None - self.cmd = ["./build/test/picoapp.elf"] - self.gw = gw - if args.startswith("nat"): - self.nat = True - else: - self.nat = False - - - if (net1): - mysock = self.parse_options(self.eth1, delay1, bw1, loss1) - if (args.startswith("dhcpclient")): - self.cmd.append("--barevde") - vdeline = "eth1:"+mysock+':' - else: - self.cmd.append("--vde") - vdeline = "eth1:"+mysock+':'+"172.16."+`self.eth1.net.n`+"."+`self.eth1.n`+":255.255.255.0:" - if (self.gw and re.search("172\.16\."+`self.eth1.net`, self.gw)): - vdeline +=self.gw+":" - self.cmd.append(vdeline) - if (net2): - mysock = self.parse_options(self.eth2, delay2, bw2, loss2) - if (args.startswith("dhcpclient")): - self.cmd.append("--barevde") - vdeline = "eth2:"+mysock+':' - else: - self.cmd.append("--vde") - vdeline = "eth2:"+mysock+':'+"172.16."+`self.eth2.net.n`+"."+`self.eth2.n`+":255.255.255.0:" - if (self.gw and re.search("172\.16\."+`self.eth2.net`+".", self.gw)): - vdeline +=self.gw+":" - self.cmd.append(vdeline) - self.args = args - self.pop = None - topology.hosts.append(self) - self.routes = [] - - - def start(self): - if self.pop: - return - for r in self.routes: - self.cmd.append(r) - self.cmd.append("-a") - self.cmd.append(self.args) - print self.cmd - self.pop = subprocess.Popen(self.cmd) - - - -def cleanup(): - try: - subprocess.call(["killall","vde_switch"]) - subprocess.call(["killall","picoapp.elf"]) - subprocess.call(["killall","wirefilter"]) - os.unlink("/tmp/topology") - except: - pass - - - -def loop(): - while(True): - time.sleep(1) - sys.exit(0) - -def sleep(n): - time.sleep(n) - -def wait(x): - if (x is None): - print("start failed: "+x.cmd) - sys.exit(1) - while (x.pop.poll() == None): - time.sleep(1) - print "Goodbye" - sys.exit(0) - -def start(T): - print "Calculating routes.." - for n in T.nets: - for h in n.hosts: - h.add_routes(T) - print "Done!" - print "Starting up..." - for n in T.nets: - for h in n.hosts: - h.start() - -try: - os.mkdir("/tmp/topology/") -except: - pass -cleanup() diff --git a/ext/picotcp/test/python/traceroute_from_linux.py b/ext/picotcp/test/python/traceroute_from_linux.py deleted file mode 100755 index 4f2f944..0000000 --- a/ext/picotcp/test/python/traceroute_from_linux.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/python -from topology import * - -''' -Add route to 172.16.0.0/16 gw 172.16.1.2 on your host machine. - -Should result in something like: -~$ traceroute 172.16.8.2 -traceroute to 172.16.8.2 (172.16.8.2), 30 hops max, 60 byte packets - 1 172.16.1.2 (172.16.1.2) 0.481 ms 0.473 ms 0.467 ms - 2 172.16.2.2 (172.16.2.2) 4.680 ms 4.702 ms 4.700 ms - 3 172.16.3.2 (172.16.3.2) 8.759 ms 8.768 ms 8.766 ms - 4 172.16.4.2 (172.16.4.2) 10.791 ms 10.789 ms 10.786 ms - 5 172.16.5.2 (172.16.5.2) 12.826 ms 12.825 ms 12.821 ms - 6 172.16.6.2 (172.16.6.2) 14.844 ms 17.858 ms 17.857 ms - 7 172.16.7.2 (172.16.7.2) 17.858 ms 14.000 ms 13.999 ms - 8 172.16.8.2 (172.16.8.2) 18.032 ms 18.029 ms 18.023 ms - -''' - - -T = Topology() -net1 = Network(T, 'nat0') -net2 = Network(T) -net3 = Network(T) -net4 = Network(T) -net5 = Network(T) -net6 = Network(T) -net7 = Network(T) -net8 = Network(T) - -router1 = Host(T, net1, net2) -router2 = Host(T, net2, net3) -router3 = Host(T, net3, net4) -router4 = Host(T, net4, net5) -router5 = Host(T, net5, net6) -router6 = Host(T, net6, net7) -router7 = Host(T, net7, net8) - -h1 = Host(T, net8) - -sleep(1) -start(T) -loop() -cleanup() diff --git a/ext/picotcp/test/python/traceroute_nat_from_linux.py b/ext/picotcp/test/python/traceroute_nat_from_linux.py deleted file mode 100755 index d88f42a..0000000 --- a/ext/picotcp/test/python/traceroute_nat_from_linux.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/python -from topology import * - -''' -Add route to 172.16.0.0/16 gw 172.16.1.2 on your host machine. - -Should result in something like: -~$ traceroute 172.16.8.2 -traceroute to 172.16.8.2 (172.16.8.2), 30 hops max, 60 byte packets - 1 172.16.1.2 (172.16.1.2) 0.481 ms 0.473 ms 0.467 ms - 2 172.16.2.2 (172.16.2.2) 4.680 ms 4.702 ms 4.700 ms - 3 172.16.3.2 (172.16.3.2) 8.759 ms 8.768 ms 8.766 ms - 4 172.16.4.2 (172.16.4.2) 10.791 ms 10.789 ms 10.786 ms - 5 172.16.5.2 (172.16.5.2) 12.826 ms 12.825 ms 12.821 ms - 6 172.16.6.2 (172.16.6.2) 14.844 ms 17.858 ms 17.857 ms - 7 172.16.7.2 (172.16.7.2) 17.858 ms 14.000 ms 13.999 ms - 8 172.16.8.2 (172.16.8.2) 18.032 ms 18.029 ms 18.023 ms - -''' - - -T = Topology() -net1 = Network(T, 'nat0') -net2 = Network(T) -net3 = Network(T) -net4 = Network(T) -net5 = Network(T) -net6 = Network(T) -net7 = Network(T) -net8 = Network(T) - -router1 = Host(T, net1, net2, args="natbox:172.16.2.1") -router2 = Host(T, net2, net3, args="natbox:172.16.3.1") -router3 = Host(T, net3, net4, args="natbox:172.16.4.1") -router4 = Host(T, net4, net5, args="natbox:172.16.5.1") -router5 = Host(T, net5, net6, args="natbox:172.16.6.1") -router6 = Host(T, net6, net7, args="natbox:172.16.7.1") -router7 = Host(T, net7, net8, args="natbox:172.16.8.1") - -h1 = Host(T, net8) - -sleep(1) -start(T) -loop() -cleanup() diff --git a/ext/picotcp/test/python/udpecho.py b/ext/picotcp/test/python/udpecho.py deleted file mode 100755 index 6ca15aa..0000000 --- a/ext/picotcp/test/python/udpecho.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -# - -from topology import * - -T = Topology() -net1 = Network(T,"udp0") -echo = Host(T, net1, args="udpecho:172.16.1.2:7770:7770:1400:") - - -sleep(1) -raw_input("Press enter to continue ...") - -start(T) -wait(echo) -cleanup() diff --git a/ext/picotcp/test/python/zmq_linux.py b/ext/picotcp/test/python/zmq_linux.py deleted file mode 100755 index 643175a..0000000 --- a/ext/picotcp/test/python/zmq_linux.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -from topology import * -import zmq -import sys - -T = Topology() -net1 = Network(T, "pyt0") - -#h1 = Host(T, net1) -h2 = Host(T, net1, args="zeromq_prod:") - -sleep(1) -raw_input("Press enter to continue ...") -start(T) - -# Zeromq part -ctx = zmq.Context() -z = ctx.socket(zmq.SUB) -z.setsockopt(zmq.SUBSCRIBE, "") -z.connect("tcp://172.16.1.2:1207") -print "In the loop..." -for i in range(20): - if z.poll(20000) == 0: - print "Timeout!!!" - cleanup() - sys.exit(1) - else: - msg = z.recv() - print "Recvd msg len=%d content: %s" % (len(msg), msg) - - - - -cleanup() diff --git a/ext/picotcp/test/test_tftp_app_client.c b/ext/picotcp/test/test_tftp_app_client.c deleted file mode 100644 index dd5ece3..0000000 --- a/ext/picotcp/test/test_tftp_app_client.c +++ /dev/null @@ -1,244 +0,0 @@ -#include -#include -#include -#include -#include -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#include "pico_socket.h" -#include "pico_stack.h" -#include "pico_device.h" -#include "pico_dev_vde.h" -#include "pico_tftp.h" - -static struct pico_device *pico_dev; - -int32_t get_filesize(const char *filename) -{ - int ret; - struct stat buf; - - ret = stat(filename, &buf); - if (ret) - return -1; - - return buf.st_size; -} - -void start_rx(struct pico_tftp_session *session, int *synchro, const char *filename, int options) -{ - int ret; - int fd; - int32_t len; - uint8_t buf[PICO_TFTP_PAYLOAD_SIZE]; - int left = 1000; - int countdown = 0; - - printf("Start receiving file %s with options set to %d\n", filename, options); - - if (options) { - ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0); - if (ret) { - fprintf(stderr, "Error in pico_tftp_set_option\n"); - exit(1); - } - } - - ret = pico_tftp_app_start_rx(session, filename); - if (ret) { - fprintf(stderr, "Error in pico_tftp_app_start_rx\n"); - exit(1); - } - - fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0664); - if (!fd) { - fprintf(stderr, "Error in open\n"); - countdown = 1; - } - - for(; left; left -= countdown) { - usleep(2000); /* PICO_IDLE(); */ - pico_stack_tick(); - if (countdown) - continue; - - if (*synchro) { - len = pico_tftp_get(session, buf, PICO_TFTP_PAYLOAD_SIZE); - if (len < 0) { - fprintf(stderr, "Failure in pico_tftp_get\n"); - close(fd); - countdown = 1; - continue; - } - - ret = write(fd, buf, len); - if (ret < 0) { - fprintf(stderr, "Error in write\n"); - pico_tftp_abort(session, TFTP_ERR_EXCEEDED, "File write error"); - close(fd); - countdown = 1; - continue; - } - - printf("Written %" PRId32 " bytes to file (synchro=%d)\n", len, *synchro); - - if (len != PICO_TFTP_PAYLOAD_SIZE) { - close(fd); - printf("Transfer complete!\n"); - countdown = 1; - } - } - } -} - -void start_tx(struct pico_tftp_session *session, int *synchro, const char *filename, int options) -{ - int ret; - int fd; - int32_t len; - uint8_t buf[PICO_TFTP_PAYLOAD_SIZE]; - int left = 1000; - int countdown = 0; - - printf("Start sending file %s with options set to %d\n", filename, options); - - if (options) { - ret = get_filesize(filename); - if (ret < 0) { - fprintf(stderr, "Error in get_filesize\n"); - exit(1); - } - - ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); - if (ret) { - fprintf(stderr, "Error in pico_tftp_set_option\n"); - exit(1); - } - } - - ret = pico_tftp_app_start_tx(session, filename); - if (ret) { - fprintf(stderr, "Error in pico_tftp_app_start_rx\n"); - exit(1); - } - - fd = open(filename, O_RDONLY, 0444); - if (!fd) { - fprintf(stderr, "Error in open\n"); - pico_tftp_abort(session, TFTP_ERR_EACC, "Error opening file"); - countdown = 1; - } - - for(; left; left -= countdown) { - usleep(2000); /* PICO_IDLE(); */ - pico_stack_tick(); - if (countdown) - continue; - - if (*synchro) { - ret = read(fd, buf, PICO_TFTP_PAYLOAD_SIZE); - if (ret < 0) { - fprintf(stderr, "Error in read\n"); - pico_tftp_abort(session, TFTP_ERR_EACC, "File read error"); - close(fd); - countdown = 1; - continue; - } - - printf("Read %" PRId32 " bytes from file (synchro=%d)\n", len, *synchro); - - len = pico_tftp_put(session, buf, ret); - if (len < 0) { - fprintf(stderr, "Failure in pico_tftp_put\n"); - close(fd); - countdown = 1; - continue; - } - - if (len != PICO_TFTP_PAYLOAD_SIZE) { - close(fd); - printf("Transfer complete!\n"); - countdown = 1; - } - } - } -} - -void usage(const char *text) -{ - fprintf(stderr, "%s\nArguments must be \n" - " can be:\n" - "\tg => GET request without options\n" - "\tG => GET request WITH options\n" - "\tp => PUT request without options\n" - "\tP => PUT request WITH options\n\n", - text); - exit(1); -} - -int main(int argc, char**argv) -{ - struct pico_ip4 my_ip; - union pico_address server_address; - struct pico_ip4 netmask; - struct pico_tftp_session *session; - int synchro; - int options = 0; - void (*operation)(struct pico_tftp_session *session, int *synchro, const char *filename, int options); - - unsigned char macaddr[6] = { - 0, 0, 0, 0xa, 0xb, 0x0 - }; - - uint16_t *macaddr_low = (uint16_t *) (macaddr + 2); - *macaddr_low = *macaddr_low ^ (uint16_t)((uint16_t)getpid() & (uint16_t)0xFFFFU); - macaddr[4] ^= (uint8_t)(getpid() >> 8); - macaddr[5] ^= (uint8_t) (getpid() & 0xFF); - - pico_string_to_ipv4("10.40.0.10", &my_ip.addr); - pico_string_to_ipv4("255.255.255.0", &netmask.addr); - pico_string_to_ipv4("10.40.0.2", &server_address.ip4.addr); - - if (argc != 3) { - usage("Invalid number or arguments"); - } - - switch (argv[2][0]) { - case 'G': - options = 1; - case 'g': - operation = start_rx; - break; - case 'P': - options = 1; - case 'p': - operation = start_tx; - break; - default: - usage("Invalid mode"); - } - - printf("%s start!\n", argv[0]); - pico_stack_init(); - pico_dev = (struct pico_device *) pico_vde_create("/tmp/vde_switch", "tap0", macaddr); - - if(!pico_dev) { - fprintf(stderr, "Error creating pico device, got enough privileges? Exiting...\n"); - exit(1); - } - - pico_ipv4_link_add(pico_dev, my_ip, netmask); - printf("Starting picoTCP loop\n"); - - session = pico_tftp_app_setup(&server_address, short_be(PICO_TFTP_PORT), PICO_PROTO_IPV4, &synchro); - if (!session) { - fprintf(stderr, "Error in pico_tftp_app_setup\n"); - exit(1); - } - - printf("synchro %d\n", synchro); - - operation(session, &synchro, argv[1], options); -} diff --git a/ext/picotcp/test/unit/modunit_pico_6lowpan.c b/ext/picotcp/test/unit/modunit_pico_6lowpan.c deleted file mode 100644 index 166dd76..0000000 --- a/ext/picotcp/test/unit/modunit_pico_6lowpan.c +++ /dev/null @@ -1,1634 +0,0 @@ -#include "pico_addressing.h" -#include "pico_ipv6_nd.h" -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_ipv6.h" -#include "pico_dev_radiotest.c" -#include "modules/pico_6lowpan_ll.c" -#include "modules/pico_6lowpan.c" -#include "pico_6lowpan_ll.h" -#include "check.h" - -#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_ethernet.h" -#include "pico_6lowpan.h" -#include "pico_802154.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" - -#include -#include -#include - -/******************************************************************************* -* MACROS -******************************************************************************/ - -#define STARTING() \ - printf("*********************** STARTING %s ***\n", __func__); \ - fflush(stdout) -#define TRYING(s, ...) \ - printf("\n=== TRYING %s: " s, __func__, ##__VA_ARGS__); \ - fflush(stdout) -#define OUTPUT() \ - do { \ - printf("\n> OUTPUT:\n"); \ - } while (0) -#define RESULTS() \ - do { \ - printf("\n> RESULTS:\n"); \ - } while (0) -#define FAIL_UNLESS(cond, i, s, ...) \ - do { \ - char str[80] = { 0 }; \ - snprintf(str, 80, "TEST %2d: "s"...", (i)++, ##__VA_ARGS__); \ - printf("%s",str); \ - if (cond) { \ - printf("%-*s %s\n", (int)(80 - strlen(str) - 12), "", "[SUCCESS]"); \ - } else { \ - printf("%-*s %s\n", (int)(80 - strlen(str) - 12), "", "[FAILED]"); \ - } \ - fflush(stdout); \ - fail_unless((int)(intptr_t)cond, s, ##__VA_ARGS__); \ - }while(0) -#define FAIL_IF(cond, i, s, ...) }\ - do { \ - char str[80] = { 0 }; \ - snprintf(str, 80, "TEST %2d: "s"...", (i)++, ##__VA_ARGS__); \ - printf(str); \ - if (!cond) { \ - printf("%-*s %s\n", (int)(80 - strlen(str) - 12), "", "[SUCCESS]"); \ - } else { \ - printf("%-*s %s\n", (int)(80 - strlen(str) - 12), "", "[FAILED]"); \ - } \ - fflush(stdout); \ - fail_if((int)(intptr_t)(cond), s, ##__VA_ARGS__); \ - }while(0) -#define ENDING(i) \ - printf("*********************** ENDING %s *** NUMBER OF TESTS: %d\n",\ - __func__, ((i)-1)); \ - fflush(stdout) -#define DBG(s, ...) \ - printf(s, ##__VA_ARGS__); \ - fflush(stdout) -static void -dbg_buffer(uint8_t *buf, size_t len) -{ - int i = 0; - printf("Buffer:"); - for (i = 0; i < (int)len; i++) { - if (i % 8 != 0) - printf("0x%02x, ", buf[i]); - else { - printf("\n0x%02x, ", buf[i]); - } - } - printf("\n"); -} - -/******************************************************************************* -* CTX -******************************************************************************/ - -START_TEST(tc_compare_prefix) -{ - int test = 1, ret = 0; - struct pico_ip6 a, b, c; - pico_string_to_ipv6("2aaa:1234:5678:9123:0:0ff:fe00:0105", a.addr); - pico_string_to_ipv6("2aaa:1234:5678:9143:0102:0304:0506:0708", b.addr); - pico_string_to_ipv6("2aaa:1234:5678:9156:0102:0304:0506:0708", c.addr); - - STARTING(); - - TRYING("With 2 equal prexixes\n"); - ret = compare_prefix(a.addr, b.addr, 54); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Prefixes are equal, should've returned 0, ret = %d",ret); - - TRYING("With b > a\n"); - ret = compare_prefix(a.addr, b.addr, 60); - RESULTS(); - FAIL_UNLESS(ret, test, "Prefixes are not equal, shouldn't have returned 0, ret = %d",ret); - - TRYING("With c > b\n"); - ret = compare_prefix(b.addr, c.addr, 64); - RESULTS(); - FAIL_UNLESS(ret, test, "Prefixes are not equal, shouldn't have returned 0, ret = %d",ret); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compare_ctx) -{ - int test = 1, ret = 0; - struct pico_ip6 a, b, c; - struct iphc_ctx ca, cb, cc; - pico_string_to_ipv6("2aaa:1234:5678:9123:0:0ff:fe00:0105", a.addr); - pico_string_to_ipv6("2aaa:1234:5678:9145:0102:0304:0506:0708", b.addr); - pico_string_to_ipv6("2aaa:1234:5678:9156:0102:0304:0506:0708", c.addr); - ca.prefix = a; - ca.size = 54; - cb.prefix = b; - cc.prefix = c; - - STARTING(); - - TRYING("With 2 equal ctx's\n"); - ret = compare_ctx(&ca, &cb); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Prefixes are equal, should've returned 0, ret = %d", ret); - - ca.size = 60; - TRYING("With b > a\n"); - ret = compare_ctx(&ca, &cb); - RESULTS(); - FAIL_UNLESS(ret, test, "Prefixes are not equal, shouln'r return 0, ret = %d", ret); - - cb.size = 64; - TRYING("With b > c\n"); - ret = compare_ctx(&cb, &cc); - RESULTS(); - FAIL_UNLESS(ret, test, "Prefixes are not equal, shouldn't return 0, ret = %d", ret); - - ENDING(test); -} -END_TEST - -START_TEST(tc_ctx_lookup) -{ - int test = 1, ret = 0; - struct pico_ip6 a, b; - struct iphc_ctx *found = NULL; - pico_string_to_ipv6("2aaa:1234:5678:9123:0:0ff:fe00:0105", a.addr); - pico_string_to_ipv6("2aaa:1234:5678:9145:0102:0304:0506:0708", b.addr); - - STARTING(); - pico_stack_init(); - - TRYING("To find a prefix in the context tree\n"); - ret = ctx_insert(a, 13, 54, 0, PICO_IPHC_CTX_COMPRESS, NULL); - found = ctx_lookup(b); - RESULTS(); - FAIL_UNLESS(!ret, test, "Inserting should've succeeded, return 0. ret = %d", ret); - FAIL_UNLESS(found, test, "Should've found the context"); - FAIL_UNLESS(found->id == 13, test, "Should've found the correct ctx, ID = %d", ret); - - ENDING(test); -} -END_TEST - -/******************************************************************************* -* IPHC -******************************************************************************/ - -#ifdef PICO_6LOWPAN_IPHC_ENABLED - -START_TEST(tc_compressor_vtf) -{ - int test = 1, ret = 0; - uint8_t ori_fl[] = {0x64,0x00,0x00,0x00}; - uint8_t ori_dscp[] = {0x62,0x00,0x00,0x00}; - uint8_t ori_notc[] = {0x60,0x0f,0xed,0xcb}; - uint8_t ori_inline[] = {0x6f,0xaf,0xed,0xcb}; - uint8_t comp_fl[] = {0x40}; - uint8_t comp_dscp[] = {0x20}; - uint8_t comp_notc[] = {0x0f,0xed,0xcb}; - uint8_t comp_inline[] = {0xfa,0x0f,0xed,0xcb}; - uint8_t comp[4] = {0, 0, 0, 0}; - uint8_t iphc[3] = {0, 0, 0}; - - STARTING(); - - TRYING("With ECN set. No matter DSCP, should elide flow label and reformat tc\n"); - ret = compressor_vtf(ori_fl, comp, iphc, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(comp, 4); - RESULTS(); - FAIL_UNLESS((iphc[0] & TF_ELIDED) == TF_ELIDED_FL, test, "Should've set the IPHC-bits correctly, %02X", iphc[0]); - FAIL_UNLESS(1 == ret, test, "Should've returned size of 1, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(comp_fl, comp, (size_t)ret), test, "inline formatting not correct"); - memset(comp, 0, 4); - memset(iphc, 0, 3); - - TRYING("With DSCP set. No matter ECN, should elide flow label and reformat tc\n"); - ret = compressor_vtf(ori_dscp, comp, iphc, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(comp, 4); - RESULTS(); - FAIL_UNLESS((iphc[0] & TF_ELIDED) == TF_ELIDED_FL, test, "Should've set the IPHC-bits correctly, %02X", iphc[0]); - FAIL_UNLESS(1 == ret, test, "Should've returned size of 1, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(comp_dscp, comp, (size_t)ret), test, "inline formatting not correct"); - memset(comp, 0, 4); - memset(iphc, 0, 3); - - TRYING("With FL set. If DSCP is not set, can be compressed to 3 bytes\n"); - ret = compressor_vtf(ori_notc, comp, iphc, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(comp, 4); - RESULTS(); - FAIL_UNLESS((iphc[0] & TF_ELIDED) == TF_ELIDED_DSCP, test, "Should've set the IPHC-bits correctly, %02X", iphc[0]); - FAIL_UNLESS(3 == ret, test, "Should've returned size of 3, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(comp_notc, comp, (size_t)ret), test, "inline formatting not correct"); - memset(comp, 0, 4); - memset(iphc, 0, 3); - - TRYING("With evt. set. Should elide nothing and reformat traffic class\n"); - ret = compressor_vtf(ori_inline, comp, iphc, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(comp, 4); - RESULTS(); - FAIL_UNLESS((iphc[0] & TF_ELIDED) == TF_INLINE, test, "Should've set the IPHC-bits correctly, %02X", iphc[0]); - FAIL_UNLESS(4 == ret, test, "Should've returned size of 4, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(comp_inline, comp, (size_t)ret), test, "inline formatting not correct"); - memset(comp, 0, 4); - memset(iphc, 0, 3); - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_vtf) -{ - int test = 1, ret = 0; - uint8_t ori_fl[] = {0x64,0x00,0x00,0x00}; - uint8_t ori_dscp[] = {0x62,0x00,0x00,0x00}; - uint8_t ori_notc[] = {0x60,0x0f,0xed,0xcb}; - uint8_t ori_inline[] = {0x6f,0xaf,0xed,0xcb}; - uint8_t comp_fl[] = {0x40}; - uint8_t comp_dscp[] = {0x20}; - uint8_t comp_notc[] = {0x0f,0xed,0xcb}; - uint8_t comp_inline[] = {0xfa,0x0f,0xed,0xcb}; - uint8_t ori[4] = {0}; - uint8_t iphc_fl[3] = {TF_ELIDED_FL, 0,0}; - uint8_t iphc_dscp[3] = {TF_ELIDED_FL, 0,0}; - uint8_t iphc_notc[3] = {TF_ELIDED_DSCP, 0,0}; - uint8_t iphc_inline[3] = {TF_INLINE, 0,0}; - - STARTING(); - - TRYING("With flow label compressed\n"); - ret = decompressor_vtf(ori, comp_fl, iphc_fl, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(ori, 4); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned length of 1, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(ori_fl, ori, (size_t)4), test, "Should've formatted IPv6 VTF-field correctly"); - memset(ori, 0, 4); - - TRYING("With flow label compression but with IPHC inline\n"); - ret = decompressor_vtf(ori, comp_dscp, iphc_dscp, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(ori, 4); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned length of 1, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(ori_dscp, ori, (size_t)4), test, "Should've formatted IPv6 VTF-field correctly"); - memset(ori, 0, 4); - - TRYING("With flow label inline and DSCP compressed\n"); - ret = decompressor_vtf(ori, comp_notc, iphc_notc, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(ori, 4); - RESULTS(); - FAIL_UNLESS(3 == ret, test, "Should've returned length of 3, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(ori_notc, ori, (size_t)4), test, "Should've formatted IPv6 VTF-field correctly"); - memset(ori, 0, 4); - - TRYING("With evt. inline\n"); - ret = decompressor_vtf(ori, comp_inline, iphc_inline, NULL, NULL, NULL); - OUTPUT(); - dbg_buffer(ori, 4); - RESULTS(); - FAIL_UNLESS(4 == ret, test, "Should've returned length of 4, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(ori_inline, ori, (size_t)4), test, "Should've formatted IPv6 VTF-field correctly"); - memset(ori, 0, 4); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compressor_nh) -{ - int test = 1; - uint8_t nxthdr = PICO_PROTO_UDP; - uint8_t iphc = 0; - uint8_t comp = 0; - int ret = 0; - - STARTING(); - - TRYING("With next header = UDP\n"); - ret = compressor_nh(&nxthdr, &comp, &iphc, NULL, NULL, NULL); - OUTPUT(); - printf("IPHC: %02X", iphc); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc == NH_COMPRESSED, test, "Should've set the IPHC bits correctly"); - FAIL_UNLESS(0 == comp, test, "Shouldn't have changed compressed"); - - TRYING("With next header = EXT_HOPBYHOP\n"); - nxthdr = PICO_IPV6_EXTHDR_HOPBYHOP; - ret = compressor_nh(&nxthdr, &comp, &iphc, NULL, NULL, NULL); - OUTPUT(); - printf("IPHC: %02X", iphc); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc == NH_COMPRESSED, test, "Should've set the IPHC bits correctly"); - FAIL_UNLESS(0 == comp, test, "Shouldn't have changed compressed"); - - TRYING("With next header = EXT_ROUTING\n"); - nxthdr = PICO_IPV6_EXTHDR_ROUTING; - ret = compressor_nh(&nxthdr, &comp, &iphc, NULL, NULL, NULL); - OUTPUT(); - printf("IPHC: %02X", iphc); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc == NH_COMPRESSED, test, "Should've set the IPHC bits correctly"); - FAIL_UNLESS(0 == comp, test, "Shouldn't have changed compressed"); - - TRYING("With next header = EXT_FRAG\n"); - nxthdr = PICO_IPV6_EXTHDR_FRAG; - ret = compressor_nh(&nxthdr, &comp, &iphc, NULL, NULL, NULL); - OUTPUT(); - printf("IPHC: %02X", iphc); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc == NH_COMPRESSED, test, "Should've set the IPHC bits correctly"); - FAIL_UNLESS(0 == comp, test, "Shouldn't have changed compressed"); - - TRYING("With next header = EXT_DSTOPT\n"); - nxthdr = PICO_IPV6_EXTHDR_DESTOPT; - ret = compressor_nh(&nxthdr, &comp, &iphc, NULL, NULL, NULL); - OUTPUT(); - printf("IPHC: %02X", iphc); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc == NH_COMPRESSED, test, "Should've set the IPHC bits correctly"); - FAIL_UNLESS(0 == comp, test, "Shouldn't have changed compressed"); - - TRYING("With next header = TCP\n"); - nxthdr = PICO_PROTO_TCP; - ret = compressor_nh(&nxthdr, &comp, &iphc, NULL, NULL, NULL); - OUTPUT(); - printf("IPHC: %02X", iphc); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc == 0, test, "Should've set the IPHC bits correctly"); - FAIL_UNLESS(PICO_PROTO_TCP == comp, test, "Shouldn't have changed compressed"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_nh) -{ - int test = 1; - uint8_t iphc = NH_COMPRESSED; - uint8_t ori = 0; - int8_t ret = 0; - uint8_t comp = PICO_PROTO_TCP; - - STARTING(); - - TRYING("With NH bit set\n"); - ret = decompressor_nh(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(0 == ori, test, "Should've filled ori with NH_COMPRESSED"); - - TRYING("With NH bit cleared\n"); - iphc = 0; - ret = decompressor_nh(&ori, &comp, &iphc, NULL, NULL, NULL); - FAIL_UNLESS(1 == ret, test, "Should've returned 1, ret = %d", ret); - FAIL_UNLESS(PICO_PROTO_TCP == ori, test, "Should've filled ori with PICO_PROTO_TCP"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compressor_hl) -{ - int test = 1; - uint8_t iphc = 0; - uint8_t ori = 1; - uint8_t comp; - int ret = 0; - - STARTING(); - - TRYING("With HL set to 1\n"); - ret = compressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(HL_COMPRESSED_1 == iphc, test, "Should've set IPHC bits correctly"); - - TRYING("With HL set to 64\n"); - ori = 64; - ret = compressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(HL_COMPRESSED_64 == iphc, test, "Should've set IPHC bits correctly"); - - TRYING("With HL set to 255\n"); - ori = 255; - ret = compressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(HL_COMPRESSED_255 == iphc, test, "Should've set IPHC bits correctly"); - - TRYING("With random HL\n"); - ori = 153; - ret = compressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned 1, ret = %d",ret); - FAIL_UNLESS(0 == iphc, test, "Should've set IPHC bits correctly"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_hl) -{ - int test = 1; - uint8_t iphc = HL_COMPRESSED_1; - uint8_t ori = 0; - uint8_t comp = 0; - int ret = 0; - - STARTING(); - - TRYING("HL 1 compressed\n"); - ret = decompressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d",ret ); - FAIL_UNLESS(1 == ori, test, "Should filled in correct hop limit"); - - TRYING("HL 64 compressed\n"); - iphc = HL_COMPRESSED_64; - ret = decompressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d",ret ); - FAIL_UNLESS(64 == ori, test, "Should filled in correct hop limit"); - - TRYING("HL 255 compressed\n"); - iphc = HL_COMPRESSED_255; - ret = decompressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d",ret ); - FAIL_UNLESS(255 == ori, test, "Should filled in correct hop limit"); - - TRYING("HL not compressed\n"); - iphc = 0; - comp = 125; - ret = decompressor_hl(&ori, &comp, &iphc, NULL, NULL, NULL); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned 0, ret = %d",ret ); - FAIL_UNLESS(125 == ori, test, "Should filled in correct hop limit"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_addr_comp_mode) -{ - uint8_t iphc[3] = { 0 }; - int test = 1, ret = 0; - struct pico_ip6 ip; - struct pico_ip6 local; - struct pico_ip6 local2; - struct pico_ip6 local3; - union pico_ll_addr addr = { .pan = { .addr.data = {1,2,3,4,5,6,7,8}, .mode = AM_6LOWPAN_SHORT }}; - struct pico_device dev = { .mode = LL_MODE_IEEE802154 }; - pico_string_to_ipv6("ff00:0:0:0:0:0:e801:100", ip.addr); - pico_string_to_ipv6("fe80:0:0:0:0102:0304:0506:0708", local.addr); - pico_string_to_ipv6("fe80:0:0:0:0:0ff:fe00:0105", local3.addr); - pico_string_to_ipv6("fe80:0:0:0:0:0ff:fe00:0102", local2.addr); - - STARTING(); - - pico_stack_init(); - - TRYING("With MAC derived address\n"); - ret = addr_comp_mode(iphc, &local2, addr, &dev, SRC_SHIFT); - OUTPUT(); - dbg_buffer(iphc, 3); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned 0, ret = %d", ret); - FAIL_UNLESS(iphc[1] & SRC_COMPRESSED, test, "Should've set IPHC bits correctly, %02X", iphc[1]); - memset(iphc, 0, 3); - - TRYING("With wrong device link layer mode\n"); - dev.mode = LL_MODE_ETHERNET; - ret = addr_comp_mode(iphc, &local2, addr, &dev, SRC_SHIFT); - RESULTS(); - FAIL_UNLESS(-1 == ret, test, "Shoudl've returned error (-1), ret = %d", ret); - memset(iphc, 0, 3); - - TRYING("With non MAC derived extended address\n"); - dev.mode = LL_MODE_IEEE802154; - ret = addr_comp_mode(iphc, &local, addr, &dev, SRC_SHIFT); - FAIL_UNLESS(8 == ret, test, "Should've return 8, ret = %d", ret); - FAIL_UNLESS(SRC_COMPRESSED_64 == iphc[1], test, "Should've set the IPHC bits correctly, iphc = %02X", iphc[1]); - memset(iphc, 0, 3); - - TRYING("With non MAC derived short address\n"); - ret = addr_comp_mode(iphc, &local3, addr, &dev, SRC_SHIFT); - FAIL_UNLESS(2 == ret, test, "should've returned 2, ret = %d", ret); - FAIL_UNLESS(SRC_COMPRESSED_16 == iphc[1], test, "Should've set the IPHC bits correctly, iphc = %02X", iphc[1]); - - ENDING(test); -} -END_TEST - -START_TEST(tc_addr_comp_prefix) -{ - int test = 1, ret = 0; - uint8_t iphc[3] = { 0 }; - struct pico_ip6 ip; - struct pico_ip6 local; - struct pico_ip6 local3; - pico_string_to_ipv6("ff00:0:0:0:0:0:e801:100", ip.addr); - pico_string_to_ipv6("fe80:0:0:0:0102:0304:0506:0708", local.addr); - pico_string_to_ipv6("2aaa:0:0:0:0:0ff:fe00:0105", local3.addr); - - STARTING(); - - pico_stack_init(); - - TRYING("With MCAST address\n"); - ret = addr_comp_prefix(iphc, &ip, 1); - RESULTS(); - FAIL_UNLESS(COMP_MULTICAST == ret, test, "Should've returned COMP_MULTICAST, ret = %d", ret); - FAIL_UNLESS(!iphc[1], test, "Shouldn't have set any IPHC bytes, iphc = %02X", iphc[1]); - memset(iphc, 0, 3); - - TRYING("With link local destination address\n"); - ret = addr_comp_prefix(iphc, &local, 0); - RESULTS(); - FAIL_UNLESS(COMP_LINKLOCAL == ret, test, "Should've returned COMP_LINKLOCAL, ret = %d", ret); - FAIL_UNLESS(!iphc[1], test, "Shouldn't have set any IPHC bytes, iphc = %02X", iphc[1]); - memset(iphc, 0, 3); - - TRYING("With a unicast address where there's no context available for\n"); - ret = addr_comp_prefix(iphc, &local3, 0); - RESULTS(); - FAIL_UNLESS(COMP_STATELESS == ret, test, "Should've return COMP_STATELESS, ret = %d", ret); - FAIL_UNLESS(!iphc[1], test, "Shouldn't have set any IPHC bytes, iphc = %02X", iphc[1]); - memset(iphc, 0,3); - - TRYING("With a unicast address where there's context available for\n"); - ctx_insert(local3, 13, 64, 0, PICO_IPHC_CTX_COMPRESS, NULL); - ret = addr_comp_prefix(iphc, &local3, 0); - FAIL_UNLESS(13 == ret, test, "Should've returned CTX ID of 13, ret = %d", ret); - FAIL_UNLESS(iphc[1] & DST_STATEFUL, test, "Should've set DAC correctly, iphc = %02X", iphc[1]); - FAIL_UNLESS(iphc[1] & CTX_EXTENSION, test, "Should've set CTX extension bit correctly, iphc = %02X", iphc[1]); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compressor_src) -{ - int test = 1; - struct pico_ip6 unspec = {{ 0 }}; - struct pico_ip6 ll_mac = {{0xfe,0x80,0,0,0,0,0,0 ,1,2,3,4,5,6,7,8}}; - struct pico_ip6 ll_nmac_16 = {{0xfe,0x80,0,0,0,0,0,0 ,0,0,0,0xff,0xfe,0,0x12,0x34}}; - struct pico_ip6 ll_nmac_64 = {{0xfe,0x80,0,0,0,0,0,0 ,8,7,6,5,4,3,2,1}}; - struct pico_ip6 ip_ctx = {{0x2a,0xaa,0,0,0,0,0,0 ,1,2,3,4,5,6,7,8}}; - struct pico_ip6 ip_stateless = {{0x2a,0xbb,0,0,0,0,0,0 ,1,2,3,4,5,6,7,8}}; - union pico_ll_addr mac = { .pan = {.addr.data = {3,2,3,4,5,6,7,8}, .mode = AM_6LOWPAN_EXT } }; - struct pico_device dev = { 0 }; - int ret = 0; - - uint8_t iphc[3] = { 0, 0, 0 }; - uint8_t buf[PICO_SIZE_IP6] = { 0 }; - - dev.mode = LL_MODE_IEEE802154; - STARTING(); - pico_stack_init(); - - TRYING("With unspecified source address, should: set SAC, clear SAM\n"); - ret = compressor_src(unspec.addr, buf, iphc, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(iphc, 3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(16 == ret, test, "Shouldn't elide unspecified address, ret = %d", ret); - FAIL_UNLESS(iphc[1] & SRC_STATEFUL, test, "Should've set SAC"); - FAIL_UNLESS((iphc[1] & SRC_COMPRESSED) == 0, test, "Should've cleared SAM"); - - TRYING("With invalid device, should indicate error\n"); - dev.mode = LL_MODE_ETHERNET; - ret = compressor_src(ll_mac.addr, buf, iphc, &mac, NULL, &dev); - RESULTS(); - FAIL_UNLESS(-1 == ret, test, "Should've indicated error, invalid device, ret = %d",ret); - - TRYING("With mac derived address, should elide fully\n"); - dev.mode = LL_MODE_IEEE802154; - ret = compressor_src(ll_mac.addr, buf, iphc, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(iphc,3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned compressed size of 0, ret = %d", ret); - FAIL_UNLESS(!(iphc[1] & SRC_STATEFUL), test, "Shoudln't have set SAC"); - FAIL_UNLESS((iphc[1] & SRC_COMPRESSED) == SRC_COMPRESSED, test, "Should set SAM to '11', iphc = %02X", iphc[1]); - - TRYING("With non mac derived 16-bit derivable address\n"); - ret = compressor_src(ll_nmac_16.addr, buf, iphc, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(iphc,3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(2 == ret, test, "Should've returned compressed size of 2, ret = %d", ret); - FAIL_UNLESS(!(iphc[1] & SRC_STATEFUL), test, "Shouldn't have set SAC"); - FAIL_UNLESS((iphc[1] & SRC_COMPRESSED) == SRC_COMPRESSED_16, test, "Should've set SAM to '10', iphc = %02X", iphc[1]); - FAIL_UNLESS(0 == memcmp(buf, ll_nmac_16.addr + 14, 2), test, "Should've copied 16 bit of source address inline"); - - TRYING("With non mac derived 64-bit derivable address\n"); - ret = compressor_src(ll_nmac_64.addr, buf, iphc, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(iphc,3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(8 == ret, test, "Should've returned compressed size of 8, ret = %d", ret); - FAIL_UNLESS(!(iphc[1] & SRC_STATEFUL), test, "Shoudln't have set SAC"); - FAIL_UNLESS((iphc[1] & SRC_COMPRESSED) == SRC_COMPRESSED_64, test, "Should've set SAM to '01', iphc = %02X", iphc[1]); - FAIL_UNLESS(0 == memcmp(buf, ll_nmac_64.addr + 8, 8), test, "Should've copied IID of source address inline"); - - TRYING("With context derived address\n"); - pico_stack_init(); - ctx_insert(ip_ctx, 13, 64, 0, PICO_IPHC_CTX_COMPRESS, NULL); - ret = compressor_src(ip_ctx.addr, buf, iphc, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(iphc, 3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned compressed size of 0, ret = %d", ret); - FAIL_UNLESS((iphc[1] & SRC_STATEFUL), test, "Shoudl've set SAC"); - FAIL_UNLESS((iphc[1] & SRC_COMPRESSED) == SRC_COMPRESSED, test, "Shoudl've set SAM to '11', iphc = %02X", iphc[1]); - FAIL_UNLESS((iphc[2] >> SRC_SHIFT) == 13, test, "Should've filled in the context extension correctly, ctx = %02X", iphc[2]); - - TRYING("With stateless compression\n"); - ret = compressor_src(ip_stateless.addr, buf, iphc, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(iphc, 3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(PICO_SIZE_IP6 == ret, test, "Should've returned compressed size of 16, ret = %d",ret); - FAIL_UNLESS((iphc[1] & SRC_STATEFUL) == 0, test, "Shoudln't have set SAC"); - FAIL_UNLESS((iphc[1] & SRC_COMPRESSED) == 0, test, "Should've set SAM to '00', iphc = %02X", iphc[1]); - FAIL_UNLESS(0 == memcmp(buf, ip_stateless.addr, PICO_SIZE_IP6), test, "Should've copied the source address inline"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_src) -{ - int test = 1; - int ret = 0; - - union pico_ll_addr mac = { .pan = {.addr.data = {3,2,3,4,5,6,7,8}, .mode = AM_6LOWPAN_EXT } }; - struct pico_device dev; - - /* Stateless compression */ - uint8_t iphc1[] = {0x00, 0x00, 0x00}; - uint8_t buf1[] = {0x2a, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - struct pico_ip6 ip1 = {{0x2a,0xbb,0,0,0,0,0,0 ,1,2,3,4,5,6,7,8}}; - - /* With context */ - uint8_t iphc2[] = {0x00, 0xf0, 0xd0}; - uint8_t buf2[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - struct pico_ip6 ip2 = {{0x2a,0xaa,0,0,0,0,0,0 ,1,2,3,4,5,6,7,8}}; - - /* Link-local non-mac 64-bit derivable address */ - uint8_t iphc4[] = {0x00, 0x10, 0x00}; - uint8_t buf4[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - struct pico_ip6 ip4 = {{0xfe,0x80,0,0,0,0,0,0 ,8,7,6,5,4,3,2,1}}; - - /* Link-local non-mac 16-bit derivable address */ - uint8_t iphc3[] = {0x00, 0x20, 0x00}; - uint8_t buf3[] = {0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - struct pico_ip6 ip3 = {{0xfe,0x80,0,0,0,0,0,0 ,0,0,0,0xff,0xfe,0,0x12,0x34}}; - - /* Link-local mac derivable address */ - uint8_t iphc5[] = {0x00, 0x30, 0x00}; - uint8_t buf5[] = {0}; - struct pico_ip6 ip5 = {{0xfe,0x80,0,0,0,0,0,0 ,1,2,3,4,5,6,7,8}}; - - /* Context non-mac 16-bit derivable address */ - uint8_t iphc6[] = {0x00, 0xE0, 0xd0}; - uint8_t buf6[] = {0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - struct pico_ip6 ip6 = {{0x2a,0xaa,0,0,0,0,0,0 ,0,0,0,0xff,0xfe,0,0x12,0x34}}; - - uint8_t buf[PICO_SIZE_IP6] = { 0 }; - dev.mode = LL_MODE_IEEE802154; - - pico_stack_init(); - STARTING(); - - TRYING("With statelessly compressed address\n"); - ret = decompressor_src(buf, buf1, iphc1, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(16 == ret, test, "Should've returned compressed size of 16, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(buf, ip1.addr, PICO_SIZE_IP6), test, "Should've correctly decompressed address"); - memset(buf, 0, PICO_SIZE_IP6); - - TRYING("With context\n"); - pico_stack_init(); - ctx_insert(ip2, 13, 64, 0, PICO_IPHC_CTX_COMPRESS, NULL); - ret = decompressor_src(buf, buf2, iphc2, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned compressed size of 0, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(buf, ip2.addr, PICO_SIZE_IP6), test, "Shoudld've correctly decompressed addresss"); - memset(buf, 0, PICO_SIZE_IP6); - - TRYING("With link-local non-mac 16-bit derivable address\n"); - ret = decompressor_src(buf, buf3, iphc3, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(2 == ret, test, "Shoudl've returned compressed size of 2, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(buf, ip3.addr, PICO_SIZE_IP6), test, "Shoudld've correctly decompressed addresss"); - memset(buf, 0, PICO_SIZE_IP6); - - TRYING("With link-local non-mac 64-bit derivable address\n"); - ret = decompressor_src(buf, buf4, iphc4, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(8 == ret, test, "Should've returned compressed size of 8, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(buf, ip4.addr, PICO_SIZE_IP6), test, "Should've correctly decompressed address"); - memset(buf, 0, PICO_SIZE_IP6); - - TRYING("With link-local mac based address\n"); - ret = decompressor_src(buf, buf5, iphc5, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(0 == ret, test, "Should've returned compressed size of 0, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(buf, ip5.addr, PICO_SIZE_IP6), test, "Should've correctly decompressed address"); - memset(buf, 0, PICO_SIZE_IP6); - - TRYING("Context based non-mac 16-bit derivable address\n"); - ret = decompressor_src(buf, buf6, iphc6, &mac, NULL, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(2 == ret, test, "Should've returned compressed size of 2, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(buf, ip6.addr, PICO_SIZE_IP6), test, "Should've correctly decompressed addresss"); - memset(buf, 0, PICO_SIZE_IP6); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compressor_dst) -{ - int test = 1; - int ret = 0; - - union pico_ll_addr mac = { .pan = {.addr.data = {3,2,3,4,5,6,7,8}, .mode = AM_6LOWPAN_EXT } }; - struct pico_device dev; - - /* Multicast 48-bit */ - struct pico_ip6 mcast1 = {{0xff,0x12,0,0,0,0,0,0 ,0,0,0,5,4,3,2,1}}; - uint8_t buf1[] = {0x12,5,4,3,2,1}; - - /* Multicast 32-bit */ - struct pico_ip6 mcast2 = {{0xFF,0x34,0,0,0,0,0,0 ,0,0,0,0,0,1,2,3}}; - uint8_t buf2[] = {0x34,1,2,3}; - - /* Multicast 8-bit */ - struct pico_ip6 mcast3 = {{0xFF,0x02,0,0,0,0,0,0 ,0,0,0,0,0,0,0,5}}; - uint8_t buf3 = 5; - - uint8_t iphc[3] = { 0 }; - uint8_t buf[PICO_SIZE_IP6] = { 0 }; - - dev.mode = LL_MODE_IEEE802154; - STARTING(); - pico_stack_init(); - - TRYING("48-bit derivable mcast address\n"); - ret = compressor_dst(mcast1.addr, buf, iphc, NULL, &mac, &dev); - OUTPUT(); - dbg_buffer(iphc, 3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(6 == ret, test, "Should've returned compressed length of 6, ret = %d", ret); - FAIL_UNLESS(iphc[1] & DST_MULTICAST, test, "Should've set IPHC mcast-flag"); - FAIL_UNLESS(!(iphc[1] & DST_STATEFUL), test, "Shouldn't have set stateful flag, iphc = %02X", iphc[1]); - FAIL_UNLESS((iphc[1] & DST_COMPRESSED) == DST_MCAST_48, test, "Should've set DAM to '01', iphc = %02X", iphc[1]); - FAIL_UNLESS(0 == memcmp(buf1, buf, 6), test, "Shoudl've correctly compressed MCAST 48 address"); - - TRYING("32-bit derivable mcast address\n"); - ret = compressor_dst(mcast2.addr, buf, iphc, NULL, &mac, &dev); - OUTPUT(); - dbg_buffer(iphc, 3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(4 == ret, test, "Should've returned compressed length of 4, ret = %d", ret); - FAIL_UNLESS(iphc[1] & DST_MULTICAST, test, "Should've set IPHC mcast-flag"); - FAIL_UNLESS(!(iphc[1] & DST_STATEFUL), test, "Shouldn't have set stateful flag, iphc = %02X", iphc[1]); - FAIL_UNLESS((iphc[1] & DST_COMPRESSED) == DST_MCAST_32, test, "Should've set DAM to '10', iphc = %02X", iphc[1]); - FAIL_UNLESS(0 == memcmp(buf2, buf, 4), test, "Shoudl've correctly compressed MCAST 32 address"); - - TRYING("8-bit derivable mcast address\n"); - ret = compressor_dst(mcast3.addr, buf, iphc, NULL, &mac, &dev); - OUTPUT(); - dbg_buffer(iphc, 3); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned compressed length of 1, ret = %d", ret); - FAIL_UNLESS(iphc[1] & DST_MULTICAST, test, "Should've set IPHC mcast-flag"); - FAIL_UNLESS(!(iphc[1] & DST_STATEFUL), test, "Shouldn't have set stateful flag, iphc = %02X", iphc[1]); - FAIL_UNLESS((iphc[1] & DST_COMPRESSED) == DST_MCAST_8, test, "Should've set DAM to '11', iphc = %02X", iphc[1]); - FAIL_UNLESS(buf[0] == buf3, test, "Shoudl've correctly compressed MCAST 32 address"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_dst) -{ - int test = 1; - int ret = 0; - - union pico_ll_addr mac = { .pan = {.addr.data = {3,2,3,4,5,6,7,8}, .mode = AM_6LOWPAN_EXT } }; - struct pico_device dev; - - /* Multicast 48-bit */ - uint8_t iphc1[3] = {0x00, 0x09, 0x00}; - struct pico_ip6 mcast1 = {{0xff,0x12,0,0,0,0,0,0 ,0,0,0,5,4,3,2,1}}; - uint8_t buf1[] = {0x12,5,4,3,2,1}; - - /* Multicast 32-bit */ - uint8_t iphc2[3] = {0x00, 0x0a, 0x00}; - struct pico_ip6 mcast2 = {{0xFF,0x34,0,0,0,0,0,0 ,0,0,0,0,0,1,2,3}}; - uint8_t buf2[] = {0x34,1,2,3}; - - /* Multicast 8-bit */ - uint8_t iphc3[3] = {0x00, 0x0b, 0x00}; - struct pico_ip6 mcast3 = {{0xFF,0x02,0,0,0,0,0,0 ,0,0,0,0,0,0,0,5}}; - uint8_t buf3[] = {5}; - - uint8_t buf[PICO_SIZE_IP6] = { 0 }; - - dev.mode = LL_MODE_IEEE802154; - STARTING(); - pico_stack_init(); - - TRYING("48-bit compressed address\n"); - ret = decompressor_dst(buf,buf1,iphc1,NULL, &mac,&dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(6 == ret, test, "Should've returned compressed length of 6, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(mcast1.addr, buf, PICO_SIZE_IP6), test, "Should've correctly decompressed the mcast address"); - - TRYING("32-bit compressed address\n"); - ret = decompressor_dst(buf,buf2,iphc2,NULL, &mac,&dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(4 == ret, test, "Should've returned compressed length of 4, ret = %d",ret); - FAIL_UNLESS(0 == memcmp(mcast2.addr, buf, PICO_SIZE_IP6), test, "Should've correctly decompressed 32-bit mcast address"); - - TRYING("8-bit compressed address\n"); - ret = decompressor_dst(buf,buf3, iphc3, NULL, &mac, &dev); - OUTPUT(); - dbg_buffer(buf, PICO_SIZE_IP6); - RESULTS(); - FAIL_UNLESS(1 == ret, test, "Should've returned compressed length of 1, ret = %d", ret); - FAIL_UNLESS(0 == memcmp(mcast3.addr, buf, PICO_SIZE_IP6), test, "Should've correctly decompressed 8-bit mcast address"); - - ENDING(test); -} -END_TEST -static const unsigned char ipv6_frame[61] = { -0x60, 0x00, 0x00, 0x00, 0x00, 0x15, 0x3c, 0xff, /* `.....<. */ -0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */ -0x02, 0x80, 0xe1, 0x03, 0x00, 0x00, 0x9d, 0x00, /* ........ */ -0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */ -0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x65, 0x63, /* ......ec */ -0x11, 0x00, 0x1e, 0x00, 0x01, 0x02, 0x00, 0x00, /* ........ */ -0x4d, 0x4c, 0x4d, 0x4c, 0x00, 0x0d, 0x7b, 0x50, /* MLML..{P */ -0xff, 0x00, 0x01, 0x01, 0x08 /* ..... */ -}; - -static const unsigned char lowpan_frame[18] = { -0x7f, 0x33, 0xe7, 0x02, 0x1e, 0x00, 0xf0, -0x4d, 0x4c, 0x4d, 0x4c, 0x7b, 0x50, 0xff, 0x00, -0x01, 0x01, 0x08 -}; - -static const unsigned char comp_frame[22] = { -0x7f, 0x33, 0xe7, 0x06, 0x1e, 0x00, 0x01, 0x02, -0x00, 0x00, 0xf0, 0x4d, 0x4c, 0x4d, 0x4c, 0x7b, -0x50, 0xff, 0x00, 0x01, 0x01, 0x08 -}; - -START_TEST(tc_compressor_iphc) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(61); - union pico_ll_addr src = { .pan = {.addr.data = {0x00,0x80,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_EXT } }; - union pico_ll_addr dst = { .pan = {.addr.data = {0x65,0x63,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_SHORT } }; - int compressed_len = 0; - struct pico_device dev; - uint8_t *buf = NULL; - uint8_t nh; - - dev.mode = LL_MODE_IEEE802154; - memcpy(f->buffer, ipv6_frame, 61); - f->net_hdr = f->buffer; - f->transport_hdr = f->buffer + 48; - f->dev = &dev; - f->src = src; - f->dst = dst; - - STARTING(); - pico_stack_init(); - - TRYING("To compress a IPv6 frame from a sample capture\n"); - buf = compressor_iphc(f, &compressed_len, &nh); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 42); - RESULTS(); - FAIL_UNLESS(2 == compressed_len, test, "Should have returned compressed_len of 2, compressed_len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, lowpan_frame, (size_t)compressed_len), test, "Should've compressed frame correctly"); - pico_frame_discard(f); - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_iphc) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(2); - union pico_ll_addr src = { .pan = {.addr.data = {0x00,0x80,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_EXT } }; - union pico_ll_addr dst = { .pan = {.addr.data = {0x65,0x63,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_SHORT } }; - struct pico_device dev; - int compressed_len = 0; - uint8_t *buf = NULL; - uint8_t hdr[40] = { - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* `.....<. */ - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */ - 0x02, 0x80, 0xe1, 0x03, 0x00, 0x00, 0x9d, 0x00, /* ........ */ - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */ - 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x65, 0x63 }; - dev.mode = LL_MODE_IEEE802154; - memcpy(f->buffer, lowpan_frame, 2); - f->net_hdr = f->buffer; - f->dev = &dev; - f->src = src; - f->dst = dst; - - STARTING(); - pico_stack_init(); - - TRYING("To decompress a 6LoWPAN frame from a sampel capture\n"); - buf = decompressor_iphc(f, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 40); - RESULTS(); - FAIL_UNLESS(2 == compressed_len, test, "Should've returned compressed_len of 2, compressed_len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, hdr, 40), test, "Should've correctly decompressed the 6LoWPAN frame"); - pico_frame_discard(f); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compressor_nhc_udp) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(8); - int compressed_len = 0; - uint8_t *buf = NULL; - - uint8_t udp1[8] = {0x4d, 0x4c, 0x4d, 0x4c, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp1[] = {0xf0, 0x4d, 0x4c, 0x4d, 0x4c, 0x7b, 0x50}; - - uint8_t udp2[8] = {0xF0, 0xb1, 0xF0, 0xb2, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp2[] = {0xf3, 0x12, 0x7b, 0x50}; - - uint8_t udp3[8] = {0xF0, 0xb1, 0x4d, 0x4c, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp3[] = {0xf2, 0xb1, 0x4d, 0x4c, 0x7b, 0x50}; - - uint8_t udp4[8] = {0x4d, 0x4c, 0xF0, 0xb2, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp4[] = {0xf1, 0x4d, 0x4c, 0xb2, 0x7b, 0x50}; - - f->transport_hdr = f->buffer; - - STARTING(); - - TRYING("To compress a UDP header from a sample capture\n"); - memcpy(f->buffer, udp1, 8); - buf = compressor_nhc_udp(f, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 7); - RESULTS(); - FAIL_UNLESS(7 == compressed_len, test, "Should've returned compressed_len of 7, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, comp1, 7), test, "Should've correctly compressed UDP header"); - - TRYING("To compress a UDP header from a sample capture with both compressible addresses\n"); - memcpy(f->buffer, udp2, 8); - buf = compressor_nhc_udp(f, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 4); - RESULTS(); - FAIL_UNLESS(4 == compressed_len, test, "Should've returned compressed_len of 4, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, comp2, 4), test, "should've correctly compressed UDP header"); - - TRYING("To compress a UDP header from a sample capture with compressible source\n"); - memcpy(f->buffer, udp3, 8); - buf = compressor_nhc_udp(f, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 6); - RESULTS(); - FAIL_UNLESS(6 == compressed_len, test, "Should've returned compressed_len of 6, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, comp3, 6), test, "should've correctly compressed UDP header"); - - TRYING("To compress a UDP header from a sample capture with compressible destination\n"); - memcpy(f->buffer, udp4, 8); - buf = compressor_nhc_udp(f, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 6); - RESULTS(); - FAIL_UNLESS(6 == compressed_len, test, "Should've returned compressed_len of 6, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, comp4, 6), test, "should've correctly compressed UDP header"); - - - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_nhc_udp) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(9); - int compressed_len = 0; - uint8_t *buf = NULL; - - uint8_t udp1[8] = {0x4d, 0x4c, 0x4d, 0x4c, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp1[] = {0xf0, 0x4d, 0x4c, 0x4d, 0x4c, 0x7b, 0x50}; - - uint8_t udp2[8] = {0xF0, 0xb1, 0xF0, 0xb2, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp2[] = {0xf3, 0x12, 0x7b, 0x50}; - - uint8_t udp3[8] = {0xF0, 0xb1, 0x4d, 0x4c, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp3[] = {0xf2, 0xb1, 0x4d, 0x4c, 0x7b, 0x50}; - - uint8_t udp4[8] = {0x4d, 0x4c, 0xF0, 0xb2, 0x00, 0x0d, 0x7b, 0x50}; - uint8_t comp4[] = {0xf1, 0x4d, 0x4c, 0xb2, 0x7b, 0x50}; - - f->transport_hdr = f->buffer; - f->net_len = PICO_SIZE_IP6HDR; - - STARTING(); - - TRYING("To decompress NH_UDP header with inline addresses\n"); - memcpy(f->buffer, comp1, 7); - f->len = 12; - buf = decompressor_nhc_udp(f, 0, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 8); - RESULTS(); - FAIL_UNLESS(7 == compressed_len, test, "Should've returned compressed_len of 7, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, udp1, 8), test, "Should've correctly compressed UDP header"); - - TRYING("To decompress NHC_UDP header with both addresses compressed\n"); - memcpy(f->buffer, comp2, 4); - f->len = 9; - buf = decompressor_nhc_udp(f, 0, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 8); - RESULTS(); - FAIL_UNLESS(4 == compressed_len, test, "Should've returned compressed_len of 4, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, udp2, 8), test, "Should've correctly decompressed UDP header"); - - TRYING("To decompress NHC_UDP header with both addresses compressed\n"); - memcpy(f->buffer, comp3, 6); - f->len = 11; - buf = decompressor_nhc_udp(f, 0, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 8); - RESULTS(); - FAIL_UNLESS(6 == compressed_len, test, "Should've returned compressed_len of 6, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, udp3, 8), test, "Should've correctly decompressed UDP header"); - - TRYING("To decompress NHC_UDP header with both addresses compressed\n"); - memcpy(f->buffer, comp4, 6); - f->len = 11; - buf = decompressor_nhc_udp(f, 0, &compressed_len); - FAIL_UNLESS(buf, test, "Should've at least returned a buffer"); - OUTPUT(); - dbg_buffer(buf, 8); - RESULTS(); - FAIL_UNLESS(6 == compressed_len, test, "Should've returned compressed_len of 6, len = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, udp4, 8), test, "Should've correctly decompressed UDP header"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_compressor_nhc_ext) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(9); - uint8_t nh = PICO_IPV6_EXTHDR_DESTOPT; - int compressed_len = 0; - uint8_t *buf = NULL; - - uint8_t ext1[8] = {0x11, 0x00, 0x1e, 0x00, 0x01, 0x02, 0x00, 0x00}; - uint8_t nhc1[8] = {0xe7, 0x06, 0x1e, 0x00, 0x01, 0x02, 0x00, 0x00}; - - f->net_hdr = f->buffer; - - STARTING(); - - TRYING("With DSTOPT extension header\n"); - memcpy(f->buffer, ext1, 8); - buf = compressor_nhc_ext(f, &compressed_len, &nh); - FAIL_UNLESS(buf, test, "Should've at least returend a buffer"); - OUTPUT(); - dbg_buffer(buf, (size_t)compressed_len); - RESULTS(); - FAIL_UNLESS(8 == compressed_len, test, "Should've returned length of 8, ret = %d", compressed_len); - FAIL_UNLESS(PICO_PROTO_UDP == nh, test, "Should've updated next header to %02X, ret = %02X", PICO_PROTO_UDP, nh); - FAIL_UNLESS(0 == memcmp(buf, nhc1, (size_t)compressed_len), test, "Should've correctly compressed next header"); - - pico_frame_discard(f); - ENDING(test); -} -END_TEST - -START_TEST(tc_decompressor_nhc_ext) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(9); - int compressed_len = 0, decomp; - uint8_t *buf = NULL; - - uint8_t ext1[8] = {0x11, 0x00, 0x1e, 0x00, 0x01, 0x02, 0x00, 0x00}; - uint8_t nhc1[8] = {0xe7, 0x02, 0x1e, 0x00, 0xf0 /* udp dispatch */}; - - f->net_hdr = f->buffer; - - STARTING(); - - TRYING("nhc_ext compressed header with dstopt extension header\n"); - memcpy(f->buffer, nhc1, 5); - buf = decompressor_nhc_ext(f, &compressed_len, &decomp); - FAIL_UNLESS(buf, test, "should've at least returend a buffer"); - OUTPUT(); - dbg_buffer(buf, 8); - RESULTS(); - FAIL_UNLESS(4 == compressed_len, test, "should've returned length of 4, ret = %d", compressed_len); - FAIL_UNLESS(0 == memcmp(buf, ext1, 8), test, "should've correctly decompressed next header"); - - pico_frame_discard(f); - ENDING(test); -} -END_TEST - -START_TEST(tc_pico_iphc_compress) -{ - int test = 1; - struct pico_frame *f = pico_frame_alloc(61); - union pico_ll_addr src = { .pan = {.addr.data = {0x00,0x80,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_EXT } }; - union pico_ll_addr dst = { .pan = {.addr.data = {0x65,0x63,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_SHORT } }; - struct pico_device dev; - struct pico_frame *new = NULL; - - dev.mode = LL_MODE_IEEE802154; - memcpy(f->buffer, ipv6_frame, 61); - f->net_hdr = f->buffer; - f->net_len = 48; - f->transport_hdr = f->buffer + 48; - f->transport_len = 8; - f->len = 61; - f->dev = &dev; - f->src = src; - f->dst = dst; - - STARTING(); - pico_stack_init(); - - TRYING("Trying to compress an IPv6 frame from an example capture\n"); - new = pico_iphc_compress(f); - FAIL_UNLESS(new, test, "Should've at least returned a frame"); - OUTPUT(); - dbg_buffer(new->net_hdr, new->len); - RESULTS(); - FAIL_UNLESS(22 == new->len, test, "Should have returned length of 22, len = %d", new->len); - FAIL_UNLESS(0 == memcmp(new->net_hdr, comp_frame, 22), test, "Should've compressed the frame correctly"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_pico_iphc_decompress) -{ - int test = 0; - struct pico_frame *f = pico_frame_alloc(61); - union pico_ll_addr src = { .pan = {.addr.data = {0x00,0x80,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_EXT } }; - union pico_ll_addr dst = { .pan = {.addr.data = {0x65,0x63,0xe1,0x03,0x00,0x00,0x9d,0x00}, .mode = AM_6LOWPAN_SHORT } }; - struct pico_device dev; - struct pico_frame *new = NULL; - - dev.mode = LL_MODE_IEEE802154; - memcpy(f->buffer, comp_frame, 22); - f->net_hdr = f->buffer; - f->net_len = 22; - f->len = 22; - f->dev = &dev; - f->src = src; - f->dst = dst; - - STARTING(); - pico_stack_init(); - - TRYING("Trying to decompress a 6LoWPAN frame from an example capture\n"); - new = pico_iphc_decompress(f); - FAIL_UNLESS(new, test, "Should've at least returned a frame"); - OUTPUT(); - dbg_buffer(new->net_hdr, new->len); - RESULTS(); - FAIL_UNLESS(61 == new->len, test, "Should've returned a length of 61, len = %d", new->len); - dbg_buffer(new->net_hdr, new->len); - FAIL_UNLESS(0 == memcmp(new->net_hdr, ipv6_frame, new->len), test, "Should've decompressed the frame correctly"); - - - ENDING(test); -} -END_TEST -#endif - -static struct pico_frame *rx = NULL; -static uint8_t tx[1500]; -static int rx_called = 0; -static int tx_called = 0; -static uint8_t tx_len = 0; - -int pico_datalink_send(struct pico_frame *f) { - dbg("Datalink_send called!\n"); - if (++tx_called == 2) { - memcpy(tx, f->start, f->len); - OUTPUT(); - dbg("tx: "); - dbg_buffer(tx, tx_len); - } - - if (f->dev->eth) { - /* If device has stack with datalink-layer pass frame through it */ - if (LL_MODE_IEEE802154 == f->dev->mode) { - return pico_enqueue(pico_proto_6lowpan.q_out, f); - } else { - return pico_enqueue(pico_proto_ethernet.q_out, f); - } - } else { - /* non-ethernet: no post-processing needed */ - return pico_sendto_dev(f); - } -} - -int32_t pico_network_receive(struct pico_frame *f) -{ - dbg("Network_receive called!\n"); - if (++rx_called == 2) - rx = pico_frame_copy(f); - - printf("RCVD frame at network layer \n"); - dbg_buffer(f->buffer, f->buffer_len); - return (int32_t)f->buffer_len; -} - -#define NUM_PING 1 - -#ifdef PICO_SUPPORT_IPV6 -static void cb_ping6(struct pico_icmp6_stats *s) -{ - char host[50]; - pico_ipv6_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("%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); - if (s->seq >= NUM_PING) - exit(0); - } else { - dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err); - exit(1); - } -} -#endif - -static void ping_abort_timer(pico_time now, void *_id) -{ - int *id = (int *) _id; - IGNORE_PARAMETER(now); - printf("Ping: aborting...\n"); - pico_icmp6_ping_abort(*id); -} - -/* Copy a string until the separator, - terminate it and return the next index, - or NULL if it encounters a EOS */ -static char *cpy_arg(char **dst, char *str) -{ - char *p, *nxt = NULL; - char *start = str; - char *end = start + strlen(start); - char sep = ','; - - p = str; - while (p) { - if ((*p == sep) || (*p == '\0')) { - *p = (char)0; - nxt = p + 1; - if ((*nxt == 0) || (nxt >= end)) - nxt = 0; - - printf("dup'ing %s\n", start); - *dst = strdup(start); - break; - } - - p++; - } - return nxt; -} - -static void app_ping(char *arg) -{ - char *dest = NULL; - char *next = NULL; - char *abort = NULL; - char *delay = NULL; - char *asize = NULL; - static int id; - int timeout = 0; - int size = 64; - - next = cpy_arg(&dest, arg); - if (!dest) { - fprintf(stderr, "ping needs the following format: ping:dst_addr:[size:[abort after N sec:[wait N sec before start]]]\n"); - exit(255); - } - if (next) { - next = cpy_arg(&asize, next); - size = atoi(asize); - if (size <= 0) { - size = 64; /* Default */ - } - } - - if (next) { - next = cpy_arg(&abort, next); - if (strlen(abort) > 0) { - printf("Got arg: '%s'\n", abort); - timeout = atoi(abort); - if (timeout < 0) { - fprintf(stderr, "ping needs the following format: ping:dst_addr:[size:[abort after N sec:[wait N sec before start]]]\n"); - exit(255); - } - printf("Aborting ping after %d seconds\n", timeout); - } - } - - if (next) { - next = cpy_arg(&delay, next); - if (strlen(delay) > 0) { - uint32_t initial_delay = (uint32_t) atoi(delay); - if (initial_delay > 0) { - printf("Initial delay: %u seconds\n", initial_delay); - initial_delay = PICO_TIME_MS() + (initial_delay * 1000); - while (PICO_TIME_MS() < initial_delay) { - pico_stack_tick(); - usleep(10000); - } - } - } - } - printf("Starting ping.\n"); - - id = pico_icmp6_ping(dest, NUM_PING, 1000, 10000, size, cb_ping6, NULL); - if (timeout > 0) { - printf("Adding abort timer after %d seconds for id %d\n", timeout, id); - if (!pico_timer_add((pico_time)(timeout * 1000), ping_abort_timer, &id)) { - printf("Failed to set ping abort timeout, aborting ping\n"); - ping_abort_timer((pico_time)0, &id); - exit(1); - } - } - - /* free copied args */ - if (dest) - free(dest); - - if (abort) - free(abort); -} - -START_TEST(tc_tx_rx) -{ - int test = 0; - struct pico_device *dev = NULL; - uint8_t n_id, n_area0, n_area1; - struct pico_ip6 myaddr, pan, netmask; - const char pan_addr[] = "2aaa:abcd::0"; - const char pan_netmask[] = "ffff:ffff:ffff:ffff::0"; - - const char *id = "3"; - const char *area0 = "1"; - const char *area1 = "0"; - char *dump = (char *)strdup("build/test/unit_6lowpan.pcap"); - char *arg = (char *)strdup("2aaa:abcd:0000:0000:0200:00aa:ab00:0001,1450,0,1,"); - - STARTING(); - - n_id = (uint8_t) atoi(id); - n_area0 = (uint8_t) atoi(area0); - n_area1 = (uint8_t) atoi(area1); - - /* Initialize picoTCP */ - pico_stack_init(); - - pico_string_to_ipv6(pan_addr, myaddr.addr); - pico_string_to_ipv6(pan_addr, pan.addr); - pico_string_to_ipv6(pan_netmask, netmask.addr); - myaddr.addr[8] = 0x02; - myaddr.addr[11] = 0xaa; - myaddr.addr[12] = 0xab; - myaddr.addr[15] = n_id; - - printf("%d:%d:%d\n", n_id, n_area0, n_area1); - dev = pico_radiotest_create(n_id, n_area0, n_area1, 1, (char *)dump); - if (!dev) { - exit(1); - } - - printf("Radiotest created.\n"); - - /* Add a routable link */ - pico_ipv6_link_add(dev, myaddr, netmask); - - /* Start ping-application */ - app_ping((char *)arg); - - printf("%s: launching PicoTCP loop\n", __FUNCTION__); - while(!rx) { - pico_stack_tick(); - usleep(2000); - } - OUTPUT(); - dbg("RX: "); - dbg_buffer(rx->start, rx->len); - RESULTS(); - tx[0] |= 0x60; - FAIL_UNLESS(0 == memcmp(rx->start, tx, rx->len), test, "Should've received exactly the same frame as was transmitted"); - - ENDING(test); -} -END_TEST - -static Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_compare_prefix = tcase_create("Unit test for compare_prefix"); - TCase *TCase_compare_ctx = tcase_create("Unit test for compare_ctx"); - TCase *TCase_ctx_lookup = tcase_create("Unit test for ctx_lookup"); - -/******************************************************************************* - * IPHC - ******************************************************************************/ -#ifdef PICO_6LOWPAN_IPHC_ENABLED - TCase *TCase_compressor_vtf = tcase_create("Unit test for compressor_vtf"); - TCase *TCase_decompressor_vtf = tcase_create("Unit test for decompressor_vtf"); - TCase *TCase_compressor_nh = tcase_create("Unit test for compressor_nh"); - TCase *TCase_decompressor_nh = tcase_create("Unit test for decompressor_nh"); - TCase *TCase_compressor_hl = tcase_create("Unit test for compressor_hl"); - TCase *TCase_decompressor_hl = tcase_create("Unit test for decompressor_hl"); - TCase *TCase_addr_comp_prefix = tcase_create("Unit test for addr_comp_prefix"); - TCase *TCase_addr_comp_mode = tcase_create("Unit test for addr_comp_mode"); - TCase *TCase_compressor_src = tcase_create("Unit test for compressor_src"); - TCase *TCase_decompressor_src = tcase_create("Unit test for decompressor_src"); - TCase *TCase_compressor_dst = tcase_create("Unit test for compressor_dst"); - TCase *TCase_decompressor_dst = tcase_create("Unit test for decompressor_dst"); - TCase *TCase_compressor_iphc = tcase_create("Unit test for compressor_iphc"); - TCase *TCase_decompressor_iphc = tcase_create("Unit test for decompressor_iphc"); - TCase *TCase_compressor_nhc_udp = tcase_create("Unit test for compressor_nhc_udp"); - TCase *TCase_decompressor_nhc_udp = tcase_create("Unit test for decompressor_nhc_udp"); - TCase *TCase_compressor_nhc_ext = tcase_create("Unit test for compressor_nhc_ext"); - TCase *TCase_decompressor_nhc_ext = tcase_create("Unit test for decompressor_nhc_ext"); - TCase *TCase_pico_iphc_compress = tcase_create("Unit test for pico_iphc_compress"); - TCase *TCase_pico_iphc_decompress = tcase_create("Unit test for pico_iphc_decompress"); -#endif - - TCase *TCase_tx_rx = tcase_create("Unit test for tx_rx"); - - tcase_add_test(TCase_compare_prefix, tc_compare_prefix); - suite_add_tcase(s, TCase_compare_prefix); - tcase_add_test(TCase_compare_ctx ,tc_compare_ctx); - suite_add_tcase(s, TCase_compare_ctx); - tcase_add_test(TCase_ctx_lookup ,tc_ctx_lookup); - suite_add_tcase(s, TCase_ctx_lookup); - -/******************************************************************************* - * IPHC - ******************************************************************************/ -#ifdef PICO_6LOWPAN_IPHC_ENABLED - tcase_add_test(TCase_compressor_vtf, tc_compressor_vtf); - suite_add_tcase(s, TCase_compressor_vtf); - tcase_add_test(TCase_decompressor_vtf, tc_decompressor_vtf); - suite_add_tcase(s, TCase_decompressor_vtf); - tcase_add_test(TCase_compressor_nh, tc_compressor_nh); - suite_add_tcase(s, TCase_compressor_nh); - tcase_add_test(TCase_decompressor_nh, tc_decompressor_nh); - suite_add_tcase(s, TCase_decompressor_nh); - tcase_add_test(TCase_compressor_hl, tc_compressor_hl); - suite_add_tcase(s, TCase_compressor_hl); - tcase_add_test(TCase_decompressor_hl, tc_decompressor_hl); - suite_add_tcase(s, TCase_decompressor_hl); - tcase_add_test(TCase_addr_comp_prefix, tc_addr_comp_prefix); - suite_add_tcase(s, TCase_addr_comp_prefix); - tcase_add_test(TCase_addr_comp_mode, tc_addr_comp_mode); - suite_add_tcase(s, TCase_addr_comp_mode); - tcase_add_test(TCase_compressor_src, tc_compressor_src); - suite_add_tcase(s, TCase_compressor_src); - tcase_add_test(TCase_decompressor_src, tc_decompressor_src); - suite_add_tcase(s, TCase_decompressor_src); - tcase_add_test(TCase_compressor_dst, tc_compressor_dst); - suite_add_tcase(s, TCase_compressor_dst); - tcase_add_test(TCase_decompressor_dst, tc_decompressor_dst); - suite_add_tcase(s, TCase_decompressor_dst); - tcase_add_test(TCase_compressor_iphc, tc_compressor_iphc); - suite_add_tcase(s, TCase_compressor_iphc); - tcase_add_test(TCase_decompressor_iphc, tc_decompressor_iphc); - suite_add_tcase(s, TCase_decompressor_iphc); - tcase_add_test(TCase_compressor_nhc_udp, tc_compressor_nhc_udp); - suite_add_tcase(s, TCase_compressor_nhc_udp); - tcase_add_test(TCase_decompressor_nhc_udp, tc_decompressor_nhc_udp); - suite_add_tcase(s, TCase_decompressor_nhc_udp); - tcase_add_test(TCase_compressor_nhc_ext, tc_compressor_nhc_ext); - suite_add_tcase(s, TCase_compressor_nhc_ext); - tcase_add_test(TCase_decompressor_nhc_ext, tc_decompressor_nhc_ext); - suite_add_tcase(s, TCase_decompressor_nhc_ext); - tcase_add_test(TCase_pico_iphc_compress, tc_pico_iphc_compress); - suite_add_tcase(s, TCase_pico_iphc_compress); - tcase_add_test(TCase_pico_iphc_decompress, tc_pico_iphc_decompress); - suite_add_tcase(s, TCase_pico_iphc_decompress); -#endif - - tcase_add_test(TCase_tx_rx ,tc_tx_rx); - suite_add_tcase(s, TCase_tx_rx); - - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_802154.c b/ext/picotcp/test/unit/modunit_pico_802154.c deleted file mode 100644 index e7d6c84..0000000 --- a/ext/picotcp/test/unit/modunit_pico_802154.c +++ /dev/null @@ -1,556 +0,0 @@ -#include "pico_addressing.h" -#include "pico_ipv6_nd.h" -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_ipv6.h" -#include "pico_6lowpan.h" -#include "modules/pico_802154.c" -#include "check.h" - -#include -#include -#include - -/******************************************************************************* - * MACROS - ******************************************************************************/ - -#define STARTING() \ - printf("*********************** STARTING %s ***\n", __func__); \ - fflush(stdout) -#define TRYING(s, ...) \ - printf("Trying %s: " s, __func__, ##__VA_ARGS__); \ - fflush(stdout) -#define CHECKING(i) \ - printf("Checking the results of test %2d in %s...", (i)++, \ - __func__); \ - fflush(stdout) -#define FAIL_UNLESS(cond, s, ...) \ - if ((cond)) { \ - printf(" SUCCESS\n"); \ - } else { \ - printf(" FAILED\n"); \ - } \ - fail_unless((cond), s, ##__VA_ARGS__) -#define FAIL_IF(cond, s, ...) \ - if (!(cond)) { \ - printf(" SUCCESS\n"); \ - } else { \ - printf(" FAILED\n"); \ - } \ - fail_if((cond), s, ##__VA_ARGS__) -#define ENDING(i) \ - printf("*********************** ENDING %s *** NUMBER OF TESTS: %d\n",\ - __func__, ((i)-1)); \ - fflush(stdout) -#define DBG(s, ...) \ - printf(s, ##__VA_ARGS__); \ - fflush(stdout) - -/******************************************************************************* - * HELPER FUNCTIONS - ******************************************************************************/ - -static void dbg_addr_ext(const char *msg, uint8_t a[SIZE_6LOWPAN_EXT]) -{ - DBG("%s: (64-bit extended address): ", msg); - DBG("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]); -} - -/******************************************************************************* - * ADDRESSES - ******************************************************************************/ - -START_TEST(tc_swap) -{ - int test = 1; - uint8_t a = 5; - uint8_t b = 1; - - STARTING(); - - // TEST 1 - TRYING("With a = %d and b = %d\n", a, b); - pico_swap(&a, &b); - CHECKING(test); - FAIL_IF(1 != a && b != 5, "Failed swapping numbers\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_802154_to_ietf) -{ - int test = 1; - struct pico_802154 a = { - .addr.data = { 1,2,3,4,5,6,7,8 }, - .mode = AM_6LOWPAN_EXT - }; - uint8_t buf[] = {8,7,6,5,4,3,2,1}; - - STARTING(); - - // TEST 1 - TRYING("Extended address mode\n"); - addr_802154_to_ietf(&a); - dbg_addr_ext("After", a.addr.data); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(a.addr.data, buf, SIZE_6LOWPAN_EXT), - "Failed converting to IETF endianness\n"); - - // TEST 2 - TRYING("Short address mode\n"); - a.mode = AM_6LOWPAN_SHORT; - addr_802154_to_ietf(&a); - dbg_addr_ext("After", a.addr.data); - CHECKING(test); - FAIL_UNLESS(a.addr._short.addr == short_be(0x0708), - "Failed converting short to IETF endianness\n"); - - // TEST 3 - TRYING("Wrong address mode\n"); - a.mode = AM_6LOWPAN_NONE; - addr_802154_to_ietf(&a); - dbg_addr_ext("After", a.addr.data); - buf[0] = 7; - buf[1] = 8; - CHECKING(test); - FAIL_UNLESS(0 == memcmp(a.addr.data, buf, SIZE_6LOWPAN_EXT), - "Should've done nothing\n"); - - ENDING(test); - -} -END_TEST - -START_TEST(tc_802154_ll_src) -{ - int test = 1; - struct pico_ip6 ip = { - .addr = {0,0,0,0,0,0,0,0, 3,2,3,4,5,6,7,8} - }; - struct pico_ip6 ip2 = { - .addr = {0,0,0,0,0,0,0,0, 0,0,0,0xff,0xfe,0,0x12,0x34} - }; - struct pico_6lowpan_info info = { - .addr_short.addr = short_be(0x1234), - .addr_ext.addr = {3,2,3,4,5,6,7,8} - }; - struct pico_device dev; - struct pico_802154 addr; - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->buffer; - - STARTING(); - - dev.eth = (struct pico_ethdev *)&info; - f->net_hdr = f->buffer; - f->dev = &dev; - dev.hostvars.lowpan_flags = PICO_6LP_FLAG_LOWPAN; - - // TEST 3 - TRYING("With an IPv6 address that is derived from MAC short address\n"); - info.addr_short.addr = short_be(0x1234); - hdr->src = ip2; - addr = addr_802154_ll_src(f); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_SHORT == addr.mode, - "Should've returned device's short address \n"); - CHECKING(test); - FAIL_UNLESS(short_be(0x1234) == addr.addr._short.addr, - "Should've copied the short address from the device\n"); - - // TEST 4 - TRYING("With an IPv6 address that is derived from MAC extended address\n"); - ip.addr[8] = 1; - hdr->src = ip; - addr = addr_802154_ll_src(f); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_EXT == addr.mode, - "Should've returned device's extended address\n"); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(info.addr_ext.addr, addr.addr._ext.addr, SIZE_6LOWPAN_EXT), - "Should've copied device's extended address\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_802154_ll_dst) -{ - int test = 1; - struct pico_ip6 ip; - struct pico_ip6 local; - struct pico_ip6 local2; - struct pico_802154 addr; - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->buffer; - struct pico_device dev; - uint8_t buf[] = {3,2,3,4,5,6,7,8}; - pico_string_to_ipv6("ff00:0:0:0:0:0:e801:100", ip.addr); - pico_string_to_ipv6("fe80:0:0:0:0102:0304:0506:0708", local.addr); - pico_string_to_ipv6("fe80:0:0:0:0:0ff:fe00:1234", local2.addr); - - STARTING(); - - f->net_hdr = f->buffer; - f->dev = &dev; - dev.hostvars.lowpan_flags = PICO_6LP_FLAG_LOWPAN; - - // TEST 1 - TRYING("With a MCAST IPv6 address, should return 0xFFFF\n"); - hdr->dst = ip; - addr = addr_802154_ll_dst(f); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_SHORT == addr.mode, - "Should've set address mode to SHORT\n"); - CHECKING(test); - FAIL_UNLESS(short_be(ADDR_802154_BCAST) == addr.addr._short.addr, - "Should've set address to BCAST\n"); - - // TEST 2 - TRYING("With a link local IPv6 address derived from an extended L2 address\n"); - hdr->dst = local; - addr = addr_802154_ll_dst(f); - dbg_addr_ext("After:", addr.addr._ext.addr); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_EXT == addr.mode, - "Should've set address mode to EXTENDED\n"); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(buf, addr.addr._ext.addr, SIZE_6LOWPAN_EXT), - "Should've copied the extended address from the IP address\n"); - - // TEST 3 - TRYING("With a link local IPv6 address derived from a short L2 address\n"); - hdr->dst = local2; - addr = addr_802154_ll_dst(f); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_SHORT == addr.mode, - "Should've set address mode to SHORT\n"); - CHECKING(test); - FAIL_UNLESS(short_be(0x1234) == addr.addr._short.addr, - "Should've copied the short address from the IP address\n"); - - /* TODO: Test getting address from neighbour table */ - - ENDING(test); -} -END_TEST - -/******************************************************************************* - * FRAME - ******************************************************************************/ - -/* Frame (123 bytes) */ -static uint8_t pkt[] = { -0x41, 0xcc, 0xa6, 0xff, 0xff, 0x8a, /* A..... */ -0x18, 0x00, 0xff, 0xff, 0xda, 0x1c, 0x00, 0x88, /* ........ */ -0x18, 0x00, 0xff, 0xff, 0xda, 0x1c, 0x00, 0xc1, /* ........ */ -0x09, 0x00, 0x02, 0x42, 0xfa, 0x40, 0x04, 0x01, /* ...B.@.. */ -0xf0, 0xb1, 0x01, 0x06, 0x6f, 0xaf, 0x48, 0x65, /* ....o.He */ -0x6c, 0x6c, 0x6f, 0x20, 0x30, 0x30, 0x36, 0x20, /* llo 006 */ -0x30, 0x78, 0x46, 0x46, 0x33, 0x43, 0x0a, 0x00, /* 0xFF3C.. */ -0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, /* ........ */ -0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, /* ...... ! */ -0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* "#$%&'() */ -0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, /* *+,-./01 */ -0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, /* 23456789 */ -0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, /* :;<=>?@A */ -0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, /* BCDEFGHI */ -0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, /* JKLMNOPQ */ -0x52, 0x53, 0x54, 0x68, 0x79 /* RSThy */ -}; - -START_TEST(tc_dst_am) -{ - int test = 1; - int ret = 0; - - STARTING(); - - // TEST 1 - TRYING("Trying to determine AM of destination addr from buffer \n"); - ret = dst_am((struct pico_802154_hdr *)pkt); - DBG("ret = %d\n", ret); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_EXT == ret, - "Should've returned the AM of an extended address\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_src_am) -{ - int test = 1; - int ret = 0; - - STARTING(); - - // TEST 1 - TRYING("Trying to determine AM of source addr from buffer \n"); - ret = src_am((struct pico_802154_hdr *)pkt); - DBG("ret = %d\n", ret); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_EXT == ret, - "Should've returned the AM of an extended address\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_802154_hdr_len) -{ - int test = 1; - int ret = 0; - - STARTING(); - - // TEST 1 - TRYING("Trying to determine length of the header from buffer\n"); - ret = frame_802154_hdr_len((struct pico_802154_hdr *)pkt); - DBG("ret = %d\n", ret); - CHECKING(test); - FAIL_UNLESS(21 == ret, - "Should've returned the correct length of the header\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_802154_src) -{ - int test = 1; - struct pico_802154_hdr *hdr; - struct pico_802154 addr; - uint8_t src[] = {0x00, 0x1C, 0xDA, 0xFF, 0xFF, 0x00, 0x18, 0x88}; - STARTING(); - - hdr = (struct pico_802154_hdr *)pkt; - - // TEST 1 - TRYING("To receive the source address from a mapped buffer\n"); - addr = frame_802154_src(hdr); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_EXT == addr.mode, - "Should've returned an extended address\n"); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(src, addr.addr._ext.addr, SIZE_6LOWPAN_EXT), - "Should've copied the extended source address\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_802154_dst) -{ - int test = 1; - struct pico_802154_hdr *hdr; - struct pico_802154 addr; - uint8_t dst[] = {0x00, 0x1C, 0xDA, 0xFF, 0xFF, 0x00, 0x18, 0x8a}; - - STARTING(); - hdr = (struct pico_802154_hdr *)pkt; - - // TEST 1 - TRYING("To receive the source address from a mapped buffer\n"); - addr = frame_802154_dst(hdr); - CHECKING(test); - FAIL_UNLESS(AM_6LOWPAN_EXT == addr.mode, - "Should've returned an extended address\n"); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(dst, addr.addr._ext.addr, SIZE_6LOWPAN_EXT), - "Should've copied the extended source address\n"); - - ENDING(test); -} -END_TEST - -START_TEST(tc_802154_format) -{ - int test = 1; - struct pico_802154 src = { - .addr.data = {0x00, 0x1C, 0xDA, 0xFF, 0xFF, 0x00, 0x18, 0x88}, - .mode = AM_6LOWPAN_EXT - }; - struct pico_802154 dst = { - .addr.data = {0x00, 0x1C, 0xDA, 0xFF, 0xFF, 0x00, 0x18, 0x8a}, - .mode = AM_6LOWPAN_EXT - }; - struct pico_6lowpan_short pan = { .addr = short_be(0xffff) }; - uint8_t buf[127] = {0}; - int i = 0; - - STARTING(); - - // TEST 1 - TRYING("To format a frame like sample capture\n"); - frame_802154_format(buf, 166, FCF_INTRA_PAN, FCF_NO_ACK_REQ, - FCF_NO_SEC, pan, src, dst); - printf("Buffer:"); - for (i = 0; i < 21; i++) { - if (i % 8 != 0) - printf("%02x ", buf[i]); - else { - printf("\n%02x ", buf[i]); - } - } - printf("\n"); - CHECKING(test); - FAIL_UNLESS(21 == frame_802154_hdr_len((struct pico_802154_hdr *)buf), - "Failed to correctly set the frame header, the length isn't right\n"); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(pkt, buf, 21), - "Failed to correctly format IEEE802.15.4 frame\n"); - - ENDING(test); -} -END_TEST -START_TEST(tc_802154_process_out) -{ - int i = 0; - int ret = 0; - int test = 1; - struct pico_802154 src = { - .addr.data = {3,2,3,4,5,6,7,8}, - .mode = AM_6LOWPAN_EXT - }; - struct pico_802154 dst = { - .addr.data = {0x00, 0x1C, 0xDA, 0xFF, 0xFF, 0x00, 0x18, 0x8a}, - .mode = AM_6LOWPAN_EXT - }; - struct pico_frame *f = pico_frame_alloc(0); - struct pico_6lowpan_info info = { - .addr_short.addr = short_be(0x1234), - .addr_ext.addr = {3,2,3,4,5,6,7,8}, - .pan_id.addr = short_be(0x1234) - }; - struct pico_device dev; - uint8_t buf[] = {0x41,0xcc,0x00,0x34,0x12,0x8a,0x18,0x00, - 0xff,0xff,0xda,0x1c,0x00,0x08,0x07,0x06, - 0x05,0x04,0x03,0x02,0x03}; - dev.eth = (struct pico_ethdev *)&info; - dev.q_out = PICO_ZALLOC(sizeof(struct pico_queue)); - f->dev = &dev; - dev.hostvars.lowpan_flags = PICO_6LP_FLAG_LOWPAN; - - STARTING(); - pico_stack_init(); - - // TEST 1 - TRYING("Trying with bare frame\n"); - f->src.pan = src; - f->dst.pan = dst; - ret = pico_802154_process_out(f); - printf("Buffer:"); - for (i = 0; i < 21; i++) { - if (i % 8 != 0) - printf("%02x ", f->datalink_hdr[i]); - else { - printf("\n%02x ", f->datalink_hdr[i]); - } - } - printf("\n"); - CHECKING(test); - FAIL_UNLESS(0 < ret, "Shouldn't have returned an error\n"); - CHECKING(test); - FAIL_UNLESS(0 == memcmp(buf, f->datalink_hdr, 21), - "Frame isn't correctly formatted\n"); - - pico_frame_discard(f); - - ENDING(test); -} -END_TEST -START_TEST(tc_802154_process_in) -{ - int ret = 0; - int test = 1; - struct pico_802154 src = { - .addr.data = {3,2,3,4,5,6,7,8}, - .mode = AM_6LOWPAN_EXT - }; - struct pico_802154 dst = { - .addr.data = {0x00, 0x1C, 0xDA, 0xFF, 0xFF, 0x00, 0x18, 0x8a}, - .mode = AM_6LOWPAN_EXT - }; - struct pico_frame *f = pico_frame_alloc(22); - uint8_t buf[] = {0x41,0xcc,0x00,0x34,0x12,0x8a,0x18,0x00, - 0xff,0xff,0xda,0x1c,0x00,0x08,0x07,0x06, - 0x05,0x04,0x03,0x02,0x03,0x60}; - memcpy(f->buffer, buf, 22); - f->src.pan = src; - f->dst.pan = dst; - - STARTING(); - pico_stack_init(); - - TRYING("Apply processing function on predefined buffer\n"); - ret = pico_802154_process_in(f); - CHECKING(test); - FAIL_UNLESS(0 < ret, "Should not return failure\n"); -} -END_TEST -static Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_swap = tcase_create("Unit test for pico_swap"); - TCase *TCase_802154_to_ietf = tcase_create("Unit test for 802154_to_ietf"); - TCase *TCase_802154_ll_src = tcase_create("Unit test for 802154_ll_src"); - TCase *TCase_802154_ll_dst = tcase_create("Unit test for 802154_ll_dst"); - TCase *TCase_802154_hdr_len = tcase_create("Unit test for 802154_hdr_len"); - TCase *TCase_src_am = tcase_create("Unit test for src_am"); - TCase *TCase_dst_am = tcase_create("Unit test for dst_am"); - TCase *TCase_802154_src = tcase_create("Unit test for 802154_src"); - TCase *TCase_802154_dst = tcase_create("Unit test for 802154_dst"); - TCase *TCase_802154_format = tcase_create("Unit test for 802154_format"); - TCase *TCase_802154_process_out = tcase_create("Unit test for 802154_process_out"); - TCase *TCase_802154_process_in = tcase_create("Unit test for 802154_process_in"); - -/******************************************************************************* - * ADDRESSES - ******************************************************************************/ - tcase_add_test(TCase_swap, tc_swap); - suite_add_tcase(s, TCase_swap); - tcase_add_test(TCase_802154_to_ietf, tc_802154_to_ietf); - suite_add_tcase(s, TCase_802154_to_ietf); - tcase_add_test(TCase_802154_ll_src, tc_802154_ll_src); - suite_add_tcase(s, TCase_802154_ll_src); - tcase_add_test(TCase_802154_ll_dst, tc_802154_ll_dst); - suite_add_tcase(s, TCase_802154_ll_dst); - -/******************************************************************************* - * FRAME - ******************************************************************************/ - tcase_add_test(TCase_802154_hdr_len, tc_802154_hdr_len); - suite_add_tcase(s, TCase_802154_hdr_len); - tcase_add_test(TCase_src_am, tc_src_am); - suite_add_tcase(s, TCase_src_am); - tcase_add_test(TCase_dst_am, tc_dst_am); - suite_add_tcase(s, TCase_dst_am); - tcase_add_test(TCase_802154_src, tc_802154_src); - suite_add_tcase(s, TCase_802154_src); - tcase_add_test(TCase_802154_dst, tc_802154_dst); - suite_add_tcase(s, TCase_802154_dst); - tcase_add_test(TCase_802154_format, tc_802154_format); - suite_add_tcase(s, TCase_802154_format); - tcase_add_test(TCase_802154_process_out, tc_802154_process_out); - suite_add_tcase(s, TCase_802154_process_out); - tcase_add_test(TCase_802154_process_in, tc_802154_process_in); - suite_add_tcase(s, TCase_802154_process_in); - - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_aodv.c b/ext/picotcp/test/unit/modunit_pico_aodv.c deleted file mode 100644 index 03bda6f..0000000 --- a/ext/picotcp/test/unit/modunit_pico_aodv.c +++ /dev/null @@ -1,545 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "modules/pico_aodv.c" -#include "check.h" - - -Suite *pico_suite(void); - -START_TEST(tc_aodv_node_compare) -{ - struct pico_aodv_node a, b; - a.dest.ip4.addr = long_be(1); - b.dest.ip4.addr = long_be(2); - - fail_if(aodv_node_compare(&a, &b) >= 0); - a.dest.ip4.addr = long_be(3); - fail_if(aodv_node_compare(&a, &b) <= 0); - b.dest.ip4.addr = long_be(3); - fail_if(aodv_node_compare(&a, &b) != 0); -} -END_TEST - -START_TEST(tc_aodv_dev_cmp) -{ - struct pico_device a, b; - a.hash = 1; - b.hash = 2; - fail_if(aodv_dev_cmp(&a, &b) >= 0); - a.hash = 3; - fail_if(aodv_dev_cmp(&a, &b) <= 0); - b.hash = 3; - fail_if(aodv_dev_cmp(&a, &b) != 0); - -} -END_TEST - -START_TEST(tc_get_node_by_addr) -{ - struct pico_aodv_node a; - union pico_address test; - a.dest.ip4.addr = long_be(10); - test.ip4.addr = long_be(10); - - pico_tree_insert(&aodv_nodes, &a); - - fail_if(get_node_by_addr(&test) != &a); - pico_tree_delete(&aodv_nodes, &a); - fail_if(get_node_by_addr(&test) != NULL); - -} -END_TEST - -static int set_bcast_link_called = 0; -void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) -{ - IGNORE_PARAMETER(link); - set_bcast_link_called++; -} - -START_TEST(tc_pico_aodv_set_dev) -{ - struct pico_device *dev = NULL; - pico_aodv_set_dev(dev); - fail_if(set_bcast_link_called != 1); -} -END_TEST - -START_TEST(tc_aodv_peer_refresh) -{ - /* TODO: test this: static int aodv_peer_refresh(struct pico_aodv_node *node, uint32_t seq) */ - struct pico_aodv_node node; - memset(&node, 0, sizeof(node)); - node.dseq = 0xFFFF; - fail_if(aodv_peer_refresh(&node, 10) != 0); /* should succeed, because SYNC flag is not yet set... */ - fail_if((node.flags & PICO_AODV_NODE_SYNC) == 0); /* Flag should be set after last call... */ - fail_if(aodv_peer_refresh(&node, 5) == 0); /* should FAIL, because seq number is lower... */ - fail_if(aodv_peer_refresh(&node, 10) == 0); /* should FAIL, because seq number is still the same... */ - fail_if(aodv_peer_refresh(&node, 15) != 0); /* should succeed, because seq number is now bigger... */ - fail_if(node.dseq != 15); -} -END_TEST - -static int called_route_add = 0; -static uint32_t route_add_gw = 0u; -static int route_add_metric = 0; -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) -{ - IGNORE_PARAMETER(link); - IGNORE_PARAMETER(netmask); - IGNORE_PARAMETER(address); - called_route_add++; - route_add_gw = gateway.addr; - route_add_metric = metric; - return 0; -} - -START_TEST(tc_aodv_elect_route) -{ - struct pico_aodv_node node; - union pico_address gateway; - memset(&node, 0, sizeof(node)); - gateway.ip4.addr = 0x55555555; - - called_route_add = 0; - aodv_elect_route(&node, NULL, 150, NULL); - fail_if(called_route_add != 1); /* Not active, should succeed */ - fail_if(route_add_gw != 0u); - fail_if(route_add_metric != 1); - - called_route_add = 0; - route_add_metric = 0; - route_add_gw = 0u; - node.flags = PICO_AODV_NODE_ROUTE_DOWN | PICO_AODV_NODE_ROUTE_UP; - aodv_elect_route(&node, &gateway, 150, NULL); - fail_if(called_route_add != 0); /* Already active, existing metric is lower */ - - called_route_add = 0; - route_add_metric = 0; - route_add_gw = 0u; - node.metric = 22; - aodv_elect_route(&node, &gateway, 15, NULL); - fail_if(called_route_add != 1); /* Already active, existing metric is higher */ - fail_if(route_add_metric != 16); - fail_if(route_add_gw != 0x55555555); - -} -END_TEST - -START_TEST(tc_aodv_peer_new) -{ - union pico_address addr; - struct pico_aodv_node *new; - addr.ip4.addr = 0x44444444; - new = aodv_peer_new(&addr); - fail_if(!new); - fail_if(!get_node_by_addr(&addr)); - pico_set_mm_failure(1); - new = aodv_peer_new(&addr); - fail_if(new); -} -END_TEST -START_TEST(tc_aodv_peer_eval) -{ - union pico_address addr; - struct pico_aodv_node *node = NULL; - /* Case 0: Creation */ - addr.ip4.addr = 0x11224433; - node = aodv_peer_eval(&addr, 0, 0); - fail_if(!node); - fail_if((node->flags & PICO_AODV_NODE_SYNC) != 0); /* Not synced! */ - - /* Case 1: retrieve, unsynced */ - node->metric = 42; - node = aodv_peer_eval(&addr, 0, 0); /* Should get existing node! */ - fail_if(!node); - fail_if(node->metric != 42); - fail_if((node->flags & PICO_AODV_NODE_SYNC) != 0); /* Not synced! */ - - - /* Case 2: new node, invalid allocation */ - addr.ip4.addr = 0x11224455; - pico_set_mm_failure(1); - node = aodv_peer_eval(&addr, long_be(10), 1); - fail_if(node); - - /* Case 3: existing node, setting the new sequence */ - addr.ip4.addr = 0x11224433; - node = aodv_peer_eval(&addr, long_be(10), 1); /* Should get existing node! */ - fail_if(node->metric != 42); - fail_if((node->flags & PICO_AODV_NODE_SYNC) == 0); - fail_if(node->dseq != 10); -} -END_TEST - -START_TEST(tc_aodv_lifetime) -{ - struct pico_aodv_node node; - pico_time now = PICO_TIME_MS(); - memset(&node, 0, sizeof(node)); - fail_if(aodv_lifetime(&node) == 0); - fail_if(node.last_seen < now); - node.last_seen = now - AODV_ACTIVE_ROUTE_TIMEOUT; - fail_if(aodv_lifetime(&node) != 0); -} -END_TEST - -static uint8_t sent_pkt_type = 0xFF; -static uint32_t dest_addr = 0; -static int pico_socket_sendto_called = 0; -static int pico_socket_sendto_extended_called = 0; -uint32_t expected_dseq = 0; -int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) -{ - uint8_t *pkt = (uint8_t *)(uintptr_t)buf; - printf("Sendto called!\n"); - pico_socket_sendto_called++; - fail_if(remote_port != short_be(PICO_AODV_PORT)); - fail_if (s != aodv_socket); - fail_if(pkt[0] > 4); - fail_if(pkt[0] < 1); - sent_pkt_type = pkt[0]; - dest_addr = ((union pico_address *)dst)->ip4.addr; - if (sent_pkt_type == AODV_TYPE_RREQ) { - /* struct pico_aodv_rreq *req = (struct pico_aodv_rreq *)(uintptr_t)buf; */ - fail_if(len != sizeof(struct pico_aodv_rreq)); - } - else if (sent_pkt_type == AODV_TYPE_RREP) { - struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *)(uintptr_t)buf; - fail_if(len != sizeof(struct pico_aodv_rrep)); - fail_if(rep->dest != 0x11111111); - fail_if(rep->orig != 0x22222222); - printf("rep->dseq= %08x, exp: %08x\n", rep->dseq, expected_dseq); - fail_if(rep->dseq != expected_dseq); - } - - return len; -} - -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) -{ - IGNORE_PARAMETER(msginfo); - pico_socket_sendto_extended_called++; - return pico_socket_sendto(s, buf, len, dst, remote_port); -} - -START_TEST(tc_aodv_send_reply) -{ - struct pico_aodv_node node; - struct pico_aodv_rreq req; - struct pico_msginfo info; - union pico_address addr; - addr.ip4.addr = 0x22222222; - memset(&node, 0, sizeof(node)); - memset(&req, 0, sizeof(req)); - memset(&info, 0, sizeof(info)); - - req.dest = 0x11111111; - req.orig = addr.ip4.addr; - req.dseq = 99; - - aodv_send_reply(&node, &req, 1, &info); - fail_if(pico_socket_sendto_called != 0); /* Call should have no effect, due to non-existing origin node */ - - /* Creating origin... */ - fail_if(aodv_peer_new(&addr) == NULL); - aodv_send_reply(&node, &req, 0, &info); - fail_if(pico_socket_sendto_called != 0); /* Call should have no effect, node non-local, non sync'd */ - - expected_dseq = long_be(pico_aodv_local_id + 1); - aodv_send_reply(&node, &req, 1, &info); - fail_if(pico_socket_sendto_called != 1); /* Call should succeed */ - pico_socket_sendto_called = 0; - - node.flags = PICO_AODV_NODE_SYNC; - node.dseq = 42; - expected_dseq = long_be(42); - aodv_send_reply(&node, &req, 0, &info); - fail_if(pico_socket_sendto_called != 1); /* Call should succeed */ - pico_socket_sendto_called = 0; -} -END_TEST - -static struct pico_ipv4_link global_link; -struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev) -{ - IGNORE_PARAMETER(dev); - if (!global_link.address.addr) - return NULL; - - printf("Setting link!\n"); - return &global_link; -} - -static struct pico_device global_dev; -static int link_find_success = 0; -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *ip4) -{ - IGNORE_PARAMETER(ip4); - if (link_find_success) - return &global_dev; - - return NULL; -} - -static int timer_set = 0; -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(arg); - IGNORE_PARAMETER(timer); - IGNORE_PARAMETER(expire); - printf("Timer set!\n"); - timer_set++; - return (uint32_t ) 0x99999999; - -} - -START_TEST(tc_aodv_send_req) -{ - struct pico_aodv_node node; - struct pico_device d; - aodv_socket = NULL; - - memset(&node, 0, sizeof(node)); - node.flags = PICO_AODV_NODE_ROUTE_DOWN | PICO_AODV_NODE_ROUTE_UP; - fail_if(aodv_send_req(&node) != 0); /* Should fail: node already active */ - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - - node.flags = 0; - fail_if(aodv_send_req(&node) != 0); /* Should fail: no devices in tree */ - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - - pico_tree_insert(&aodv_devices, &d); - fail_if(aodv_send_req(&node) != -1); /* Should fail: aodv_socket == NULL */ - fail_if(pico_err != PICO_ERR_EINVAL); - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - - - /* No valid link, timer is set, call does not send packets */ - aodv_socket = (struct pico_socket*) 1; - global_link.address.addr = 0; - fail_if(aodv_send_req(&node) != 0); - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - fail_if(timer_set != 1); - timer_set = 0; - - - /* One valid link, timer is set, one packet is sent */ - global_link.address.addr = 0xFEFEFEFE; - fail_if(aodv_send_req(&node) != 1); - fail_if(pico_socket_sendto_called != 1); - fail_if(pico_socket_sendto_extended_called != 1); - fail_if(timer_set != 1); - pico_socket_sendto_called = 0; - pico_socket_sendto_extended_called = 0; - timer_set = 0; - -} -END_TEST - -START_TEST(tc_aodv_reverse_path_discover) -{ - struct pico_aodv_node node; - memset(&node, 0, sizeof(node)); - aodv_reverse_path_discover(0, &node); -} -END_TEST - -START_TEST(tc_aodv_recv_valid_rreq) -{ - struct pico_aodv_node node; - struct pico_aodv_rreq req; - struct pico_msginfo info; - union pico_address addr; - memset(&node, 0, sizeof(node)); - memset(&req, 0, sizeof(req)); - memset(&info, 0, sizeof(info)); - - addr.ip4.addr = 0x22222222; - - link_find_success = 0; - aodv_recv_valid_rreq(&node, &req, &info); - fail_if(pico_socket_sendto_called > 0); - - /* link not local, but active node, set to send reply, no timer */ - link_find_success = 0; - fail_if(aodv_peer_new(&addr) == NULL); - global_link.address.addr = 0x44444444; - req.orig = addr.ip4.addr; - req.dest = 0x11111111; - node.flags = PICO_AODV_NODE_SYNC | PICO_AODV_NODE_ROUTE_UP | PICO_AODV_NODE_ROUTE_DOWN; - node.dseq = 42; - expected_dseq = long_be(42); - aodv_recv_valid_rreq(&node, &req, &info); - fail_if(pico_socket_sendto_called < 1); - fail_if(timer_set > 0); - pico_socket_sendto_called = 0; - - /* link local, active node. Full send + set timer. */ - link_find_success = 1; - expected_dseq = long_be(pico_aodv_local_id + 1); - aodv_peer_new(&addr); - aodv_recv_valid_rreq(&node, &req, &info); - fail_if(pico_socket_sendto_called < 1); - fail_if(timer_set < 1); - -} -END_TEST - -START_TEST(tc_aodv_parse_rreq) -{ - /* TODO: test this: static void aodv_parse_rreq(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) */ -} -END_TEST - -START_TEST(tc_aodv_parse_rrep) -{ - /* TODO: test this: static void aodv_parse_rrep(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) */ -} -END_TEST - -START_TEST(tc_aodv_parse_rerr) -{ - /* TODO: test this: static void aodv_parse_rerr(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) */ -} -END_TEST - -START_TEST(tc_aodv_parse_rack) -{ - aodv_parse_rack(NULL, NULL, 0, NULL); -} -END_TEST - -START_TEST(tc_pico_aodv_parse) -{ -} -END_TEST - -START_TEST(tc_pico_aodv_socket_callback) -{ - /* TODO: test this: static void pico_aodv_socket_callback(uint16_t ev, struct pico_socket *s) */ -} -END_TEST - -START_TEST(tc_aodv_make_rreq) -{ - /* TODO: test this: static void aodv_make_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req) */ -} -END_TEST - -START_TEST(tc_aodv_retrans_rreq) -{ - /* TODO: test this: static void aodv_retrans_rreq(pico_time now, void *arg) */ -} -END_TEST - -START_TEST(tc_pico_aodv_expired) -{ - /* TODO: test this: static void pico_aodv_expired(struct pico_aodv_node *node) */ -} -END_TEST - -START_TEST(tc_pico_aodv_collector) -{ - /* TODO: test this: static void pico_aodv_collector(pico_time now, void *arg) */ -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_aodv_node_compare = tcase_create("Unit test for aodv_node_compare"); - TCase *TCase_aodv_dev_cmp = tcase_create("Unit test for aodv_dev_cmp"); - TCase *TCase_get_node_by_addr = tcase_create("Unit test for get_node_by_addr"); - TCase *TCase_pico_aodv_set_dev = tcase_create("Unit test for pico_aodv_set_dev"); - TCase *TCase_aodv_peer_refresh = tcase_create("Unit test for aodv_peer_refresh"); - TCase *TCase_aodv_elect_route = tcase_create("Unit test for aodv_elect_route"); - TCase *TCase_aodv_peer_new = tcase_create("Unit test for aodv_peer_new"); - TCase *TCase_aodv_peer_eval = tcase_create("Unit test for aodv_peer_eval"); - TCase *TCase_aodv_lifetime = tcase_create("Unit test for aodv_lifetime"); - TCase *TCase_aodv_send_reply = tcase_create("Unit test for aodv_send_reply"); - TCase *TCase_aodv_send_req = tcase_create("Unit test for aodv_send_req"); - TCase *TCase_aodv_reverse_path_discover = tcase_create("Unit test for aodv_reverse_path_discover"); - TCase *TCase_aodv_recv_valid_rreq = tcase_create("Unit test for aodv_recv_valid_rreq"); - TCase *TCase_aodv_parse_rreq = tcase_create("Unit test for aodv_parse_rreq"); - TCase *TCase_aodv_parse_rrep = tcase_create("Unit test for aodv_parse_rrep"); - TCase *TCase_aodv_parse_rerr = tcase_create("Unit test for aodv_parse_rerr"); - TCase *TCase_aodv_parse_rack = tcase_create("Unit test for aodv_parse_rack"); - TCase *TCase_pico_aodv_parse = tcase_create("Unit test for pico_aodv_parse"); - TCase *TCase_pico_aodv_socket_callback = tcase_create("Unit test for pico_aodv_socket_callback"); - TCase *TCase_aodv_make_rreq = tcase_create("Unit test for aodv_make_rreq"); - TCase *TCase_aodv_retrans_rreq = tcase_create("Unit test for aodv_retrans_rreq"); - TCase *TCase_pico_aodv_expired = tcase_create("Unit test for pico_aodv_expired"); - TCase *TCase_pico_aodv_collector = tcase_create("Unit test for pico_aodv_collector"); - - - tcase_add_test(TCase_aodv_node_compare, tc_aodv_node_compare); - suite_add_tcase(s, TCase_aodv_node_compare); - tcase_add_test(TCase_aodv_dev_cmp, tc_aodv_dev_cmp); - suite_add_tcase(s, TCase_aodv_dev_cmp); - tcase_add_test(TCase_get_node_by_addr, tc_get_node_by_addr); - suite_add_tcase(s, TCase_get_node_by_addr); - tcase_add_test(TCase_pico_aodv_set_dev, tc_pico_aodv_set_dev); - suite_add_tcase(s, TCase_pico_aodv_set_dev); - tcase_add_test(TCase_aodv_peer_refresh, tc_aodv_peer_refresh); - suite_add_tcase(s, TCase_aodv_peer_refresh); - tcase_add_test(TCase_aodv_elect_route, tc_aodv_elect_route); - suite_add_tcase(s, TCase_aodv_elect_route); - tcase_add_test(TCase_aodv_peer_new, tc_aodv_peer_new); - suite_add_tcase(s, TCase_aodv_peer_new); - tcase_add_test(TCase_aodv_peer_eval, tc_aodv_peer_eval); - suite_add_tcase(s, TCase_aodv_peer_eval); - tcase_add_test(TCase_aodv_lifetime, tc_aodv_lifetime); - suite_add_tcase(s, TCase_aodv_lifetime); - tcase_add_test(TCase_aodv_send_reply, tc_aodv_send_reply); - suite_add_tcase(s, TCase_aodv_send_reply); - tcase_add_test(TCase_aodv_send_req, tc_aodv_send_req); - suite_add_tcase(s, TCase_aodv_send_req); - tcase_add_test(TCase_aodv_reverse_path_discover, tc_aodv_reverse_path_discover); - suite_add_tcase(s, TCase_aodv_reverse_path_discover); - tcase_add_test(TCase_aodv_recv_valid_rreq, tc_aodv_recv_valid_rreq); - suite_add_tcase(s, TCase_aodv_recv_valid_rreq); - tcase_add_test(TCase_aodv_parse_rreq, tc_aodv_parse_rreq); - suite_add_tcase(s, TCase_aodv_parse_rreq); - tcase_add_test(TCase_aodv_parse_rrep, tc_aodv_parse_rrep); - suite_add_tcase(s, TCase_aodv_parse_rrep); - tcase_add_test(TCase_aodv_parse_rerr, tc_aodv_parse_rerr); - suite_add_tcase(s, TCase_aodv_parse_rerr); - tcase_add_test(TCase_aodv_parse_rack, tc_aodv_parse_rack); - suite_add_tcase(s, TCase_aodv_parse_rack); - tcase_add_test(TCase_pico_aodv_parse, tc_pico_aodv_parse); - suite_add_tcase(s, TCase_pico_aodv_parse); - tcase_add_test(TCase_pico_aodv_socket_callback, tc_pico_aodv_socket_callback); - suite_add_tcase(s, TCase_pico_aodv_socket_callback); - tcase_add_test(TCase_aodv_make_rreq, tc_aodv_make_rreq); - suite_add_tcase(s, TCase_aodv_make_rreq); - tcase_add_test(TCase_aodv_retrans_rreq, tc_aodv_retrans_rreq); - suite_add_tcase(s, TCase_aodv_retrans_rreq); - tcase_add_test(TCase_pico_aodv_expired, tc_pico_aodv_expired); - suite_add_tcase(s, TCase_pico_aodv_expired); - tcase_add_test(TCase_pico_aodv_collector, tc_pico_aodv_collector); - suite_add_tcase(s, TCase_pico_aodv_collector); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_dev_loop.c b/ext/picotcp/test/unit/modunit_pico_dev_loop.c deleted file mode 100644 index 5bec073..0000000 --- a/ext/picotcp/test/unit/modunit_pico_dev_loop.c +++ /dev/null @@ -1,97 +0,0 @@ -#include "modules/pico_dev_loop.c" -#include "check.h" -static int called = 0; -static int fail = 0; - -Suite *pico_suite(void); - -int pico_device_init(struct pico_device __attribute__((unused)) *dev, const char __attribute__((unused)) *name, const uint8_t __attribute__((unused)) *mac) -{ - if (fail) - return -1; - - return 0; -} - -void pico_device_destroy(struct pico_device *dev) -{ - dev = dev; -} - -int32_t pico_stack_recv(struct pico_device __attribute__((unused)) *dev, uint8_t __attribute__((unused)) *buffer, uint32_t __attribute__((unused)) len) -{ - called = 1; - return 1; -} - -START_TEST(tc_pico_loop_send) -{ - uint8_t buf[LOOP_MTU + 1] = {}; - fail_if(pico_loop_send(NULL, buf, LOOP_MTU + 1) != 0); - - /* First send: OK */ - fail_if(pico_loop_send(NULL, buf, LOOP_MTU) != LOOP_MTU); - - /* Second: buffer busy */ - fail_if(pico_loop_send(NULL, buf, LOOP_MTU) != 0); - -} -END_TEST - -START_TEST(tc_pico_loop_poll) -{ - uint8_t buf[LOOP_MTU + 1] = {}; - fail_if(pico_loop_poll(NULL, 0) != 0); - called = 0; - /* First send: OK */ - fail_if(pico_loop_send(NULL, buf, LOOP_MTU) != LOOP_MTU); - fail_if(pico_loop_poll(NULL, 1) != 0); - fail_if(called == 0); -} -END_TEST - -START_TEST(tc_pico_loop_create) -{ - -#ifdef PICO_FAULTY - printf("Testing with faulty memory in pico_loop_create (1)\n"); - pico_set_mm_failure(1); - fail_if(pico_loop_create() != NULL); -#endif - fail = 1; - fail_if(pico_loop_create() != NULL); - fail = 0; - fail_if(pico_loop_create() == NULL); - -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_loop_send = tcase_create("Unit test for pico_loop_send"); - TCase *TCase_pico_loop_poll = tcase_create("Unit test for pico_loop_poll"); - TCase *TCase_pico_loop_create = tcase_create("Unit test for pico_loop_create"); - - - tcase_add_test(TCase_pico_loop_send, tc_pico_loop_send); - suite_add_tcase(s, TCase_pico_loop_send); - tcase_add_test(TCase_pico_loop_poll, tc_pico_loop_poll); - suite_add_tcase(s, TCase_pico_loop_poll); - tcase_add_test(TCase_pico_loop_create, tc_pico_loop_create); - suite_add_tcase(s, TCase_pico_loop_create); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_dev_ppp.c b/ext/picotcp/test/unit/modunit_pico_dev_ppp.c deleted file mode 100644 index 499ed8c..0000000 --- a/ext/picotcp/test/unit/modunit_pico_dev_ppp.c +++ /dev/null @@ -1,1387 +0,0 @@ -#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" -#include "modules/pico_dev_ppp.c" -#include "check.h" - -struct pico_device_ppp _ppp = {}; -static enum ppp_modem_event ppp_modem_ev; -static enum ppp_lcp_event ppp_lcp_ev; -static enum ppp_auth_event ppp_auth_ev; -static enum ppp_ipcp_event ppp_ipcp_ev; - -static uint32_t called_picotimer = 0; - -Suite *pico_suite(void); - -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(arg); - IGNORE_PARAMETER(timer); - IGNORE_PARAMETER(expire); - - called_picotimer++; - - return called_picotimer; -} - - -static void modem_state(struct pico_device_ppp *ppp, enum ppp_modem_event event) -{ - IGNORE_PARAMETER(ppp); - printf("Called MODEM FSM mock\n"); - ppp_modem_ev = event; -} -static void lcp_state(struct pico_device_ppp *ppp, enum ppp_lcp_event event) -{ - IGNORE_PARAMETER(ppp); - printf("Called LCP FSM mock\n"); - ppp_lcp_ev = event; -} -static void auth_state(struct pico_device_ppp *ppp, enum ppp_auth_event event) -{ - IGNORE_PARAMETER(ppp); - printf("Called AUTH FSM mock\n"); - ppp_auth_ev = event; -} -static void ipcp_state(struct pico_device_ppp *ppp, enum ppp_ipcp_event event) -{ - IGNORE_PARAMETER(ppp); - printf("Called IPCP FSM mock\n"); - ppp_ipcp_ev = event; -} - -static int called_serial_send = 0; -static uint8_t serial_out_first_char = 0; -static uint32_t serial_out_len = 0; -static uint8_t serial_buffer[64]; - -static int unit_serial_send(struct pico_device *dev, const void *buf, int len) -{ - IGNORE_PARAMETER(dev); - printf("Called send function!\n"); - serial_out_len = (unsigned) len; - if (len < 64) { - memcpy(serial_buffer, buf, (unsigned) len); - } else { - memcpy(serial_buffer, buf, 64); - } - - serial_out_first_char = *(uint8_t *)((uintptr_t)(buf)); - called_serial_send++; - printf(" First char : %02x, len: %d\n", serial_out_first_char, serial_out_len); - printf(" ---- %02x %02x %02x %02x %02x %02x %02x %02x\n", - serial_buffer[0], serial_buffer[1], serial_buffer[2], - serial_buffer[3], serial_buffer[4], serial_buffer[5], - serial_buffer[6], serial_buffer[7]); - return len; -} - -uint8_t test_string[5][10] = { - { 0x7e, 'a', 'b', 'c', 'd', 0x7e }, - { 0x7e, 'a', 0x7e, 'c', 'd', 0x7e }, - { 0x7e, 'a', 'b', 0x7d, 'd', 0x7e }, - { 0x7e, 0x7d, 'b', 'c', 0x7e, 0x7e }, - { 0x7e, 0xed, 0x7d, 0xff, 0x7d, 0x3F, 'c', 0x20, 0x7e } -}; - -uint8_t escape_string[5][12] = { - { 0x7e, 'a', 'b', 'c', 'd', 0x7e }, - { 0x7e, 'a', 0x7d, 0x5e, 'c', 'd', 0x7e }, - { 0x7e, 'a', 'b', 0x7d, 0x5d, 'd', 0x7e }, - { 0x7e, 0x7d, 0x5d, 'b', 'c', 0x7d, 0x5e, 0x7e }, - { 0x7e, 0xed, 0x7d, 0x5d, 0xff, 0x7d, 0x5d, 0x3F, 'c', 0x20, 0x7e } -}; - -int test_string_len[] = { - 6, 6, 6, 6, 9 -}; -int escape_string_len[] = { - 6, 7, 7, 8, 11 -}; - -START_TEST(tc_ppp_serial_send_escape) -{ - int i; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - for (i = 0; i < 5; i++) { - called_serial_send = 0; - fail_if(ppp_serial_send_escape(&_ppp, test_string[i], test_string_len[i]) != test_string_len[i]); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != (unsigned) escape_string_len[i]); - printf(" test string ---- %02x %02x %02x %02x %02x %02x %02x %02x\n", - test_string[i][0], test_string[i][1], test_string[i][2], - test_string[i][3], test_string[i][4], test_string[i][5], - test_string[i][6], test_string[i][7]); - printf(" expected string ---- %02x %02x %02x %02x %02x %02x %02x %02x\n", - escape_string[i][0], escape_string[i][1], escape_string[i][2], - escape_string[i][3], escape_string[i][4], escape_string[i][5], - escape_string[i][6], escape_string[i][7]); - printf(" received string ---- %02x %02x %02x %02x %02x %02x %02x %02x\n", - serial_buffer[0], serial_buffer[1], serial_buffer[2], - serial_buffer[3], serial_buffer[4], serial_buffer[5], - serial_buffer[6], serial_buffer[7]); - - fail_if(memcmp(escape_string[i], serial_buffer, serial_out_len) != 0); - } -} -END_TEST - - -START_TEST(tc_lcp_timer_start) -{ - - /* Reset counter, LCP REQ */ - memset(&_ppp, 0, sizeof(_ppp)); - lcp_timer_start(&_ppp, 0); - fail_if(_ppp.timer_on != PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_count != 0); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); - - /* LCP CONFIG REQ, Normal case */ - memset(&_ppp, 0, sizeof(_ppp)); - lcp_timer_start(&_ppp, PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_on != PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_count != PICO_PPP_DEFAULT_MAX_CONFIGURE); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); - - /* LCP TERMINATE REQ, Normal case */ - memset(&_ppp, 0, sizeof(_ppp)); - lcp_timer_start(&_ppp, PPP_TIMER_ON_LCPTERM); - fail_if(_ppp.timer_on != PPP_TIMER_ON_LCPTERM); - fail_if(_ppp.timer_count != PICO_PPP_DEFAULT_MAX_TERMINATE); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); -} -END_TEST -START_TEST(tc_lcp_zero_restart_count) -{ - /* Reset counter, LCP REQ */ - memset(&_ppp, 0, sizeof(_ppp)); - lcp_zero_restart_count(&_ppp); - fail_if(_ppp.timer_on != PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_count != 0); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); -} -END_TEST -START_TEST(tc_lcp_timer_stop) -{ - /* LCP CONFIG REQ, Normal case */ - memset(&_ppp, 0, sizeof(_ppp)); - lcp_timer_start(&_ppp, PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_on != PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_count != PICO_PPP_DEFAULT_MAX_CONFIGURE); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); - /* Releasing timer */ - lcp_timer_stop(&_ppp, PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_on != 0); -} -END_TEST -START_TEST(tc_ppp_ctl_packet_size) -{ - uint32_t size = 10; - uint32_t prefix = ppp_ctl_packet_size(&_ppp, 0, &size); - fail_if(prefix != (PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE)); - fail_if(size != (10 + prefix + PPP_FCS_SIZE + 1)); -} -END_TEST -START_TEST(tc_ppp_fcs_char) -{ - char a = '*'; - uint16_t fcs; - fcs = ppp_fcs_char(0u, (uint8_t)a); - fail_if(fcs != 36440); -} -END_TEST -START_TEST(tc_ppp_fcs_continue) -{ - char a = '*'; - uint16_t fcs; - fcs = ppp_fcs_continue(0, (uint8_t *) &a, 1); - fail_if(fcs != 36440); -} -END_TEST -START_TEST(tc_ppp_fcs_finish) -{ - uint16_t fcs = 36440; - fcs = ppp_fcs_finish(fcs); - fail_if (fcs != 29095); -} -END_TEST -START_TEST(tc_ppp_fcs_start) -{ - uint16_t fcs; - char s = '*'; - fcs = ppp_fcs_start((uint8_t*)&s, 1); - fail_if(fcs != 33247); -} -END_TEST -START_TEST(tc_ppp_fcs_verify) -{ - char hello[8] = "hello"; - uint16_t fcs = ppp_fcs_start((uint8_t *)hello, 5); - fcs = ppp_fcs_finish(fcs); - memcpy(hello + 5, &fcs, 2); - fail_if(0 != ppp_fcs_verify((uint8_t *)hello, 7)); - hello[0] = 'B'; - hello[1] = 'y'; - hello[2] = 'e'; - hello[3] = 'z'; - hello[4] = 'z'; - fail_if(-1 != ppp_fcs_verify((uint8_t *)hello, 7)); - -} -END_TEST -START_TEST(tc_pico_ppp_ctl_send) -{ - uint8_t pkt[32] = { }; - memset(&_ppp, 0, sizeof(_ppp)); - - /* No serial_send associated */ - fail_if(pico_ppp_ctl_send(&_ppp.dev, 1, pkt, 30) != 30); - fail_if(called_serial_send != 0); - /* normal case */ - _ppp.serial_send = unit_serial_send; - fail_if(pico_ppp_ctl_send(&_ppp.dev, 1, pkt, 30) != 30); - fail_if(called_serial_send != 1); - called_serial_send = 0; - fail_if(serial_out_first_char != 0x7e); - fail_if(serial_out_len != 30); -} -END_TEST -START_TEST(tc_pico_ppp_send) -{ - uint8_t pkt[32] = { }; - memset(&_ppp, 0, sizeof(_ppp)); - - - /* wrong ipcp_state */ - _ppp.serial_send = unit_serial_send; - fail_if(pico_ppp_send(&_ppp.dev, pkt, 30) != 30); - fail_if(called_serial_send != 0); - - /* No serial_send associated */ - _ppp.serial_send = NULL; - _ppp.ipcp_state = PPP_IPCP_STATE_OPENED; - fail_if(pico_ppp_send(&_ppp.dev, pkt, 30) != 30); - fail_if(called_serial_send != 0); - - /* normal case */ - _ppp.serial_send = unit_serial_send; - fail_if(pico_ppp_send(&_ppp.dev, pkt, 30) != 30); - fail_if(called_serial_send != 1); - called_serial_send = 0; - fail_if(serial_out_first_char != 0x7e); - fail_if(serial_out_len != 38); - - /* with LCPOPT_PROTO_COMP set */ - called_serial_send = 0; - LCPOPT_SET_PEER((&_ppp), LCPOPT_PROTO_COMP); - fail_if(pico_ppp_send(&_ppp.dev, pkt, 30) != 30); - fail_if(called_serial_send != 1); - called_serial_send = 0; - fail_if(serial_out_first_char != 0x7e); - fail_if(serial_out_len != 37); - LCPOPT_UNSET_PEER((&_ppp), LCPOPT_PROTO_COMP); - - /* with LCPOPT_ADDRCTL_COMP set */ - called_serial_send = 0; - LCPOPT_SET_PEER((&_ppp), LCPOPT_ADDRCTL_COMP); - fail_if(pico_ppp_send(&_ppp.dev, pkt, 30) != 30); - fail_if(called_serial_send != 1); - called_serial_send = 0; - fail_if(serial_out_first_char != 0x7e); - fail_if(serial_out_len != 36); - LCPOPT_UNSET_PEER((&_ppp), LCPOPT_ADDRCTL_COMP); - -} -END_TEST -START_TEST(tc_ppp_modem_start_timer) -{ - memset(&_ppp, 0, sizeof(_ppp)); - ppp_modem_start_timer(&_ppp); - fail_if(_ppp.timer_on != PPP_TIMER_ON_MODEM); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); -} -END_TEST -START_TEST(tc_ppp_modem_send_reset) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_reset(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_reset(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 5); - -} -END_TEST -START_TEST(tc_ppp_modem_send_echo) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_echo(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_echo(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 6); -} -END_TEST -START_TEST(tc_ppp_modem_send_creg) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_creg(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_creg(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 11); -} -END_TEST -START_TEST(tc_ppp_modem_send_cgreg) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_cgreg(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_cgreg(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 12); -} -END_TEST -START_TEST(tc_ppp_modem_send_cgdcont) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_cgdcont(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_cgdcont(&_ppp); - fail_if(called_serial_send != 1); -} -END_TEST -START_TEST(tc_ppp_modem_send_cgatt) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_cgatt(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_cgatt(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 12); -} -END_TEST -START_TEST(tc_ppp_modem_send_dial) -{ - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - /* No serial send */ - ppp_modem_send_dial(&_ppp); - fail_if(called_serial_send > 0); - /* Normal way */ - _ppp.serial_send = unit_serial_send; - ppp_modem_send_dial(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 13); -} -END_TEST - -START_TEST(tc_ppp_modem_connected) -{ - memset(&_ppp, 0, sizeof(_ppp)); - ppp_lcp_ev = 0; - ppp_modem_connected(&_ppp); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_UP); -} -END_TEST -START_TEST(tc_ppp_modem_disconnected) -{ - memset(&_ppp, 0, sizeof(_ppp)); - ppp_lcp_ev = 0; - ppp_modem_disconnected(&_ppp); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_DOWN); -} -END_TEST -START_TEST(tc_ppp_modem_recv) -{ - char ok[] = "OK"; - char connect[] = "CONNECT HELLO HI THERE"; - char error[] = "ERROR"; - char blabla[] = "Blabla"; - ppp_modem_ev = 0; - ppp_modem_recv(&_ppp, ok, (uint32_t)strlen(ok)); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_OK); - - ppp_modem_ev = 0; - ppp_modem_recv(&_ppp, connect, (uint32_t)strlen(connect)); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_CONNECT); - - ppp_modem_ev = 0; - ppp_modem_recv(&_ppp, error, (uint32_t)strlen(error)); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_STOP); - - ppp_modem_ev = PPP_MODEM_EVENT_MAX; /* Which is basically illegal, just to check */ - ppp_modem_recv(&_ppp, blabla, (uint32_t)8); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_MAX); - -} -END_TEST -START_TEST(tc_lcp_send_configure_request) -{ - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - /* With no options... */ - called_serial_send = 0; - lcp_send_configure_request(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 12); - - /* With all the options... */ - called_serial_send = 0; - LCPOPT_SET_LOCAL((&_ppp), LCPOPT_PROTO_COMP); - LCPOPT_SET_LOCAL((&_ppp), LCPOPT_MRU); - LCPOPT_SET_LOCAL((&_ppp), LCPOPT_ADDRCTL_COMP); - lcp_send_configure_request(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 20); - - /* with a failing malloc... */ - pico_set_mm_failure(1); - called_serial_send = 0; - lcp_send_configure_request(&_ppp); - fail_if(called_serial_send != 0); - -} -END_TEST -START_TEST(tc_lcp_optflags) -{ - uint8_t pkt[4 + sizeof(struct pico_lcp_hdr)]; - uint8_t *p = pkt + sizeof(struct pico_lcp_hdr); - p[0] = 0x03; - p[1] = 0x42; - p[2] = 0x56; - p[3] = 0x99; - memset(&_ppp, 0, sizeof(_ppp)); - fail_if(lcp_optflags(&_ppp, pkt, 4 + sizeof(struct pico_lcp_hdr), 1u) != 0x08); - fail_if(_ppp.auth != 0x5699); -} -END_TEST - -START_TEST(tc_lcp_send_configure_ack) -{ - uint8_t pkt[20] = ""; - struct pico_lcp_hdr *lcpreq; - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - _ppp.pkt = pkt; - _ppp.len = 4; - lcpreq = (struct pico_lcp_hdr *)_ppp.pkt; - lcpreq->len = short_be(4); - lcp_send_configure_ack(&_ppp); - fail_if(called_serial_send != 1); -} -END_TEST -START_TEST(tc_lcp_send_terminate_request) -{ - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - called_serial_send = 0; - lcp_send_terminate_request(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 12); - -} -END_TEST -START_TEST(tc_lcp_send_terminate_ack) -{ - uint8_t pkt[20] = ""; - struct pico_lcp_hdr *lcpreq; - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - _ppp.pkt = pkt; - _ppp.len = 4; - lcpreq = (struct pico_lcp_hdr *)_ppp.pkt; - lcpreq->len = short_be(4); - lcp_send_terminate_ack(&_ppp); - fail_if(called_serial_send != 1); -} -END_TEST -START_TEST(tc_lcp_send_configure_nack) -{ - uint8_t pkt[20] = ""; - struct pico_lcp_hdr *lcpreq; - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - _ppp.pkt = pkt; - _ppp.len = 4; - lcpreq = (struct pico_lcp_hdr *)_ppp.pkt; - lcpreq->len = short_be(4); - lcp_send_configure_nack(&_ppp); - fail_if(called_serial_send != 1); -} -END_TEST -START_TEST(tc_lcp_process_in) -{ - uint8_t pkt[64]; - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - /* Receive ACK (RCA) */ - ppp_lcp_ev = 0; - pkt[0] = PICO_CONF_ACK; - lcp_process_in(&_ppp, pkt, 64); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_RCA); - - /* Receive NACK (RCN) */ - ppp_lcp_ev = 0; - pkt[0] = PICO_CONF_NAK; - lcp_process_in(&_ppp, pkt, 64); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_RCN); - - /* Receive REJ (RCN) */ - ppp_lcp_ev = 0; - pkt[0] = PICO_CONF_REJ; - lcp_process_in(&_ppp, pkt, 64); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_RCN); - - /* Receive REQ, with unwanted option field (RCR-) */ - ppp_lcp_ev = 0; - pkt[0] = PICO_CONF_REQ; - pkt[sizeof(struct pico_lcp_hdr)] = 0x04; - pkt[sizeof(struct pico_lcp_hdr) + 1] = 0x02; - lcp_process_in(&_ppp, pkt, sizeof(struct pico_lcp_hdr) + 2); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_RCR_NEG); - - /* Receive REQ, with valid option field (RCR+) */ - ppp_lcp_ev = 0; - pkt[0] = PICO_CONF_REQ; - pkt[sizeof(struct pico_lcp_hdr)] = 0x04; - pkt[sizeof(struct pico_lcp_hdr) + 1] = 0x02; - _ppp.lcpopt_local = (1 << 4); - lcp_process_in(&_ppp, pkt, sizeof(struct pico_lcp_hdr) + 2); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_RCR_POS); -} -END_TEST -START_TEST(tc_pap_process_in) -{ - struct pico_pap_hdr hdr; - memset(&_ppp, 0, sizeof(_ppp)); - - /* Receive SUCCESS (RAA) */ - _ppp.auth = 0xc023; - ppp_auth_ev = 0; - hdr.code = PAP_AUTH_ACK; - pap_process_in(&_ppp, (uint8_t *)&hdr, sizeof(hdr)); - fail_if (ppp_auth_ev != PPP_AUTH_EVENT_RAA); - - /* Receive FAILURE (RAN) */ - ppp_auth_ev = 0; - hdr.code = PAP_AUTH_NAK; - pap_process_in(&_ppp, (uint8_t *)&hdr, sizeof(hdr)); - fail_if (ppp_auth_ev != PPP_AUTH_EVENT_RAN); -} -END_TEST -START_TEST(tc_chap_process_in) -{ - struct pico_chap_hdr hdr; - memset(&_ppp, 0, sizeof(_ppp)); - - /* Receive challenge (RAC) */ - ppp_auth_ev = 0; - _ppp.auth = 0xc223; - hdr.code = CHAP_CHALLENGE; - chap_process_in(&_ppp, (uint8_t *)&hdr, sizeof(hdr)); - fail_if (ppp_auth_ev != PPP_AUTH_EVENT_RAC); - - /* Receive SUCCESS (RAA) */ - ppp_auth_ev = 0; - hdr.code = CHAP_SUCCESS; - chap_process_in(&_ppp, (uint8_t *)&hdr, sizeof(hdr)); - fail_if (ppp_auth_ev != PPP_AUTH_EVENT_RAA); - - /* Receive FAILURE (RAN) */ - ppp_auth_ev = 0; - hdr.code = CHAP_FAILURE; - chap_process_in(&_ppp, (uint8_t *)&hdr, sizeof(hdr)); - fail_if (ppp_auth_ev != PPP_AUTH_EVENT_RAN); - -} -END_TEST - -START_TEST(tc_ipcp_ack) -{ - /* TODO: test this: static void ipcp_ack(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) */ - uint8_t pkt[20] = ""; - struct pico_ipcp_hdr *ipcp; - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - _ppp.pkt = pkt; - _ppp.len = 4; - ipcp = (struct pico_ipcp_hdr *)_ppp.pkt; - ipcp->len = short_be(4); - ipcp_send_ack(&_ppp); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 12); - -} -END_TEST -START_TEST(tc_uint32_t) -{ - memset(&_ppp, 0, sizeof(_ppp)); - fail_if(ipcp_request_options_size(&_ppp) != 3 * IPCP_ADDR_LEN); - - _ppp.ipcp_nbns1 = 1; - fail_if(ipcp_request_options_size(&_ppp) != 4 * IPCP_ADDR_LEN); - - _ppp.ipcp_nbns2 = 1; - fail_if(ipcp_request_options_size(&_ppp) != 5 * IPCP_ADDR_LEN); - -} -END_TEST -START_TEST(tc_ipcp_request_add_address) -{ - uint8_t dst[6]; - ipcp_request_add_address(dst, 0x42, 0xDDCCBBAA); - fail_if(dst[0] != 0x42); - fail_if(dst[1] != IPCP_ADDR_LEN); - fail_if(dst[2] != 0xAA); - fail_if(dst[3] != 0xBB); - fail_if(dst[4] != 0xCC); - fail_if(dst[5] != 0xDD); -} -END_TEST - -START_TEST(tc_ipcp_request_fill) -{ - - uint8_t opts[5 * IPCP_ADDR_LEN]; - memset(&_ppp, 0, sizeof(_ppp)); - - _ppp.ipcp_allowed_fields = 0xffff; - ipcp_request_fill(&_ppp, opts); - fail_if(opts[0] != IPCP_OPT_IP); - fail_if(opts[6] != IPCP_OPT_DNS1); - fail_if(opts[12] != IPCP_OPT_DNS2); - - _ppp.ipcp_nbns1 = 1; - ipcp_request_fill(&_ppp, opts); - fail_if(opts[0] != IPCP_OPT_IP); - fail_if(opts[6] != IPCP_OPT_DNS1); - fail_if(opts[12] != IPCP_OPT_DNS2); - fail_if(opts[18] != IPCP_OPT_NBNS1); - - _ppp.ipcp_nbns2 = 1; - ipcp_request_fill(&_ppp, opts); - fail_if(opts[0] != IPCP_OPT_IP); - fail_if(opts[6] != IPCP_OPT_DNS1); - fail_if(opts[12] != IPCP_OPT_DNS2); - fail_if(opts[18] != IPCP_OPT_NBNS1); - fail_if(opts[24] != IPCP_OPT_NBNS2); -} -END_TEST -START_TEST(tc_ipcp_send_req) -{ - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - /* With no options... */ - called_serial_send = 0; - ipcp_send_req(&_ppp); - fail_if(called_serial_send != 1); -} -END_TEST - -START_TEST(tc_ipcp_reject_vj) -{ - /* TODO: test this: static void ipcp_reject_vj(struct pico_device_ppp *ppp, uint8_t *comp_req) */ - uint8_t buf[IPCP_OPT_VJ + sizeof(struct pico_ipcp_hdr)] = { }; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - called_serial_send = 0; - ipcp_reject_vj(&_ppp, buf); - fail_if(called_serial_send != 1); - fail_if(serial_out_len != 18); -} -END_TEST -START_TEST(tc_ppp_ipv4_conf) -{ - /* TODO: test this: static void ppp_ipv4_conf(struct pico_device_ppp *ppp) */ - /* This test needs an actual device */ -} -END_TEST - -START_TEST(tc_ipcp_process_in) -{ - /* TODO: test this: static void ipcp_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) */ - uint8_t req[sizeof(struct pico_ipcp_hdr) + 5 * IPCP_ADDR_LEN]; - uint8_t *p = req + sizeof(struct pico_ipcp_hdr); - ; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - /* * * ACK * * */ - req[0] = PICO_CONF_ACK; - - /* Fill addresses */ - *(p++) = IPCP_OPT_IP; - *(p++) = IPCP_ADDR_LEN; - *(((uint32_t*)p)) = 0x11223344; - p += sizeof(uint32_t); - - *(p++) = IPCP_OPT_DNS1; - *(p++) = IPCP_ADDR_LEN; - *(((uint32_t*)p)) = 0x55667788; - p += sizeof(uint32_t); - - *(p++) = IPCP_OPT_NBNS1; - *(p++) = IPCP_ADDR_LEN; - *(((uint32_t*)p)) = 0x99AABBCC; - p += sizeof(uint32_t); - - *(p++) = IPCP_OPT_DNS2; - *(p++) = IPCP_ADDR_LEN; - *(((uint32_t*)p)) = 0xDDEEFF00; - p += sizeof(uint32_t); - - *(p++) = IPCP_OPT_NBNS2; - *(p++) = IPCP_ADDR_LEN; - *(((uint32_t*)p)) = 0x11223344; - p += sizeof(uint32_t); - - ppp_ipcp_ev = 0; - ipcp_process_in(&_ppp, req, sizeof(req)); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_RCA); - fail_if(_ppp.ipcp_ip != 0x11223344); - fail_if(_ppp.ipcp_dns1 != 0x55667788); - fail_if(_ppp.ipcp_nbns1 != 0x99aabbcc); - fail_if(_ppp.ipcp_dns2 != 0xddeeff00); - fail_if(_ppp.ipcp_nbns2 != 0x11223344); - - /* Get a VJ reject ! */ - ppp_ipcp_ev = 0; - called_serial_send = 0; - p = req + sizeof(struct pico_ipcp_hdr); - *(p++) = IPCP_OPT_VJ; - *(p++) = IPCP_VJ_LEN; - *(((uint32_t*)p)) = 0x1; - ipcp_process_in(&_ppp, req, sizeof(struct pico_ipcp_hdr) + IPCP_VJ_LEN); - fail_if(called_serial_send != 1); - fail_if(ppp_ipcp_ev != 0); - - /* * * REQ * * */ - ppp_ipcp_ev = 0; - req[0] = PICO_CONF_REQ; - ipcp_process_in(&_ppp, req, sizeof(struct pico_ipcp_hdr)); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_RCR_POS); - - /* * * NAK * * */ - ppp_ipcp_ev = 0; - req[0] = PICO_CONF_NAK; - ipcp_process_in(&_ppp, req, sizeof(struct pico_ipcp_hdr)); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_RCN); - - /* * * REJ * * */ - ppp_ipcp_ev = 0; - req[0] = PICO_CONF_REJ; - ipcp_process_in(&_ppp, req, sizeof(struct pico_ipcp_hdr)); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_RCN); - -} -END_TEST - -START_TEST(tc_ipcp6_process_in) -{ - /* TODO: test this: static void ipcp6_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len) */ - /* When implemented, do... */ - uint8_t req[sizeof(struct pico_ipcp_hdr)]; - ppp_ipcp_ev = 0; - req[0] = PICO_CONF_REJ; - ipcp6_process_in(&_ppp, req, sizeof(struct pico_ipcp_hdr)); - fail_if(ppp_ipcp_ev != 0); -} -END_TEST - -START_TEST(tc_ppp_process_packet_payload) -{ - /* Empty, tested with ppp_process_packet, below. */ -} -END_TEST -START_TEST(tc_ppp_process_packet) -{ - /* Empty, tested with ppp_recv_data, below. */ -} -END_TEST -START_TEST(tc_ppp_recv_data) -{ - uint8_t pkt[20] = ""; - struct pico_lcp_hdr *lcpreq; - - /* This creates an LCP ack */ - printf("Unit test: Packet forgery. Creating LCP ACK... \n"); - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - _ppp.pkt = pkt; - _ppp.len = 4; - lcpreq = (struct pico_lcp_hdr *)_ppp.pkt; - lcpreq->len = short_be(4); - lcp_send_configure_ack(&_ppp); - fail_if(called_serial_send != 1); - /* LCP ack is now in the buffer, and can be processed */ - printf("Unit test: Packet forgery. Injecting LCP ACK... \n"); - ppp_lcp_ev = 0; - ppp_recv_data(&_ppp, serial_buffer + 1, serial_out_len - 2); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_RCA); - printf("OK!\n"); - /* TODO: Increase coverage. */ -} -END_TEST - -START_TEST(tc_lcp_this_layer_up) -{ - /* TODO: test this: static void lcp_this_layer_up(struct pico_device_ppp *ppp) */ - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - - ppp_auth_ev = 0; - lcp_this_layer_up(&_ppp); - fail_if(ppp_auth_ev != PPP_AUTH_EVENT_UP_NONE); - - ppp_auth_ev = 0; - _ppp.auth = 0xc023; - lcp_this_layer_up(&_ppp); - fail_if(ppp_auth_ev != PPP_AUTH_EVENT_UP_PAP); - - ppp_auth_ev = 0; - _ppp.auth = 0xc223; - lcp_this_layer_up(&_ppp); - fail_if(ppp_auth_ev != PPP_AUTH_EVENT_UP_CHAP); - - ppp_auth_ev = 0; - _ppp.auth = 0xfefe; - lcp_this_layer_up(&_ppp); - fail_if(ppp_auth_ev != 0); -} -END_TEST -START_TEST(tc_lcp_this_layer_down) -{ - ppp_auth_ev = 0; - lcp_this_layer_down(&_ppp); - fail_if(ppp_auth_ev != PPP_AUTH_EVENT_DOWN); -} -END_TEST -START_TEST(tc_lcp_this_layer_started) -{ - ppp_modem_ev = 0; - lcp_this_layer_started(&_ppp); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_START); -} -END_TEST -START_TEST(tc_lcp_this_layer_finished) -{ - ppp_modem_ev = 0; - lcp_this_layer_finished(&_ppp); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_STOP); -} -END_TEST -START_TEST(tc_lcp_initialize_restart_count) -{ - /* TODO: test this: static void lcp_initialize_restart_count(struct pico_device_ppp *ppp) */ - memset(&_ppp, 0, sizeof(_ppp)); - lcp_initialize_restart_count(&_ppp); - fail_if(_ppp.timer_on != PPP_TIMER_ON_LCPREQ); - fail_if(_ppp.timer_count != PICO_PPP_DEFAULT_MAX_CONFIGURE); - fail_if(_ppp.timer_val != PICO_PPP_DEFAULT_TIMER); -} -END_TEST -START_TEST(tc_lcp_send_code_reject) -{ - /* TODO: test this: static void lcp_send_code_reject(struct pico_device_ppp *ppp) */ - lcp_send_code_reject(&_ppp); -} -END_TEST -START_TEST(tc_lcp_send_echo_reply) -{ - uint8_t pkt[20] = ""; - struct pico_lcp_hdr *lcpreq; - called_serial_send = 0; - memset(&_ppp, 0, sizeof(_ppp)); - _ppp.serial_send = unit_serial_send; - _ppp.pkt = pkt; - _ppp.len = 4; - lcpreq = (struct pico_lcp_hdr *)_ppp.pkt; - lcpreq->len = short_be(4); - lcp_send_echo_reply(&_ppp); - fail_if(called_serial_send != 1); -} -END_TEST -START_TEST(tc_auth) -{ - ppp_ipcp_ev = 0; - auth(&_ppp); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_UP); -} -END_TEST -START_TEST(tc_deauth) -{ - ppp_ipcp_ev = 0; - deauth(&_ppp); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_DOWN); -} -END_TEST -START_TEST(tc_auth_req) -{ - auth_req(&_ppp); -} -END_TEST -START_TEST(tc_auth_rsp) -{ - uint8_t req[sizeof(struct pico_chap_hdr) + 1 + CHAP_MD5_SIZE] = { - 0 - }; /* 21 bytes */ - struct pico_chap_hdr *hdr = (struct pico_chap_hdr *)req; - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - _ppp.serial_send = unit_serial_send; - - _ppp.auth = 0xc223; /* hardcode CHAP */ - hdr->code = CHAP_CHALLENGE; - hdr->len = short_be((uint16_t)(sizeof (struct pico_chap_hdr) + CHAP_MD5_SIZE)); - req[sizeof(struct pico_chap_hdr)] = CHAP_MD5_SIZE; /* CHAP value size field */ - _ppp.pkt = req; - _ppp.len = sizeof(struct pico_chap_hdr) + CHAP_MD5_SIZE; - auth_rsp(&_ppp); - fail_if(called_serial_send != 1); - printf("OK!\n"); - -} -END_TEST -START_TEST(tc_auth_start_timer) -{ - memset(&_ppp, 0, sizeof(_ppp)); - auth_start_timer(&_ppp); - fail_if(_ppp.timer_on != PPP_TIMER_ON_AUTH); - -} -END_TEST -START_TEST(tc_ipcp_send_ack) -{ - uint8_t req[sizeof(struct pico_chap_hdr) + 4 ]; - struct pico_ipcp_hdr *hdr = (struct pico_ipcp_hdr *)req; - memset(&_ppp, 0, sizeof(_ppp)); - called_serial_send = 0; - _ppp.serial_send = unit_serial_send; - hdr->code = PICO_CONF_REQ; - hdr->len = short_be((uint16_t)(sizeof (struct pico_ipcp_hdr) + 4)); - _ppp.pkt = req; - _ppp.len = sizeof(struct pico_chap_hdr) + 4; - ipcp_send_ack(&_ppp); - fail_if(called_serial_send != 1); - printf("OK!\n"); -} -END_TEST -START_TEST(tc_ipcp_send_nack) -{ - ipcp_send_nack(&_ppp); -} -END_TEST -START_TEST(tc_ipcp_bring_up) -{ - memset(&_ppp, 0, sizeof(_ppp)); - /* without address */ - ipcp_bring_up(&_ppp); - - /* with address */ - _ppp.ipcp_ip = 0xAABBCCDD; - ipcp_bring_up(&_ppp); -} -END_TEST -START_TEST(tc_ipcp_bring_down) -{ - /* TODO: test this: static void ipcp_bring_down(struct pico_device_ppp *ppp) */ - ipcp_bring_down(&_ppp); -} -END_TEST -START_TEST(tc_ipcp_start_timer) -{ - memset(&_ppp, 0, sizeof(_ppp)); - ipcp_start_timer(&_ppp); - fail_if (_ppp.timer_on != PPP_TIMER_ON_IPCP); - fail_if (_ppp.timer_val != PICO_PPP_DEFAULT_TIMER * PICO_PPP_DEFAULT_MAX_FAILURE); -} -END_TEST -START_TEST(tc_pico_ppp_poll) -{ - /* TODO: test this: static int pico_ppp_poll(struct pico_device *dev, int loop_score) */ -} -END_TEST -START_TEST(tc_pico_ppp_link_state) -{ - memset(&_ppp, 0, sizeof(_ppp)); - fail_if(pico_ppp_link_state(&_ppp.dev) != 0); - _ppp.ipcp_state = PPP_IPCP_STATE_OPENED; - fail_if(pico_ppp_link_state(&_ppp.dev) == 0); -} -END_TEST -START_TEST(tc_check_to_modem) -{ - ppp_modem_ev = 0; - memset(&_ppp, 0, sizeof(_ppp)); - /* No timer on ... */ - check_to_modem(&_ppp); - fail_if(ppp_modem_ev != 0); - - /* Timer set to 1 */ - _ppp.timer_on = PPP_TIMER_ON_MODEM; - _ppp.timer_val = 1; - check_to_modem(&_ppp); - fail_if(ppp_modem_ev != 0); - _ppp.timer_val--; - /* Timer expired */ - check_to_modem(&_ppp); - printf("Modem event: %02x\n", ppp_modem_ev); - fail_if(ppp_modem_ev != PPP_MODEM_EVENT_TIMEOUT); - -} -END_TEST -START_TEST(tc_check_to_lcp) -{ - ppp_lcp_ev = 0; - memset(&_ppp, 0, sizeof(_ppp)); - /* No timer on ... */ - check_to_lcp(&_ppp); - fail_if(ppp_lcp_ev != 0); - - /* Count set to 1 */ - _ppp.timer_count = 1; - - /* Timer set to 1 */ - _ppp.timer_on = PPP_TIMER_ON_LCPTERM; - _ppp.timer_val = 1; - check_to_lcp(&_ppp); - fail_if(ppp_lcp_ev != 0); - _ppp.timer_val--; - /* Timer expired */ - check_to_lcp(&_ppp); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_TO_POS); - - /* Timer set to 1 */ - ppp_lcp_ev = 0; - _ppp.timer_on = PPP_TIMER_ON_LCPREQ; - _ppp.timer_val = 1; - check_to_lcp(&_ppp); - fail_if(ppp_lcp_ev != 0); - _ppp.timer_val--; - /* Timer expired */ - check_to_lcp(&_ppp); - fail_if(ppp_lcp_ev != PPP_LCP_EVENT_TO_NEG); -} -END_TEST -START_TEST(tc_check_to_auth) -{ - /* TODO: test this: static void check_to_auth(struct pico_device_ppp *ppp) */ - ppp_auth_ev = 0; - memset(&_ppp, 0, sizeof(_ppp)); - /* No timer on ... */ - check_to_auth(&_ppp); - fail_if(ppp_auth_ev != 0); - - /* Timer set to 1 */ - _ppp.timer_on = PPP_TIMER_ON_AUTH; - _ppp.timer_val = 1; - check_to_auth(&_ppp); - fail_if(ppp_auth_ev != 0); - /* Timer expired */ - _ppp.timer_val--; - check_to_auth(&_ppp); - fail_if(ppp_auth_ev != PPP_AUTH_EVENT_TO); -} -END_TEST -START_TEST(tc_check_to_ipcp) -{ - ppp_ipcp_ev = 0; - memset(&_ppp, 0, sizeof(_ppp)); - /* No timer on ... */ - check_to_ipcp(&_ppp); - fail_if(ppp_ipcp_ev != 0); - - /* Timer set to 1 */ - _ppp.timer_on = PPP_TIMER_ON_IPCP; - _ppp.timer_val = 1; - check_to_ipcp(&_ppp); - fail_if(ppp_ipcp_ev != 0); - /* Timer expired */ - _ppp.timer_val--; - check_to_ipcp(&_ppp); - fail_if(ppp_ipcp_ev != PPP_IPCP_EVENT_TO); -} -END_TEST - -START_TEST(tc_pico_ppp_tick) -{ - called_picotimer = 0; - memset(&_ppp, 0, sizeof(_ppp)); - pico_ppp_tick(0, &_ppp); - fail_if(called_picotimer != 1); -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_ppp_serial_send_escape = tcase_create("Unit test for ppp_serial_send_escape"); - TCase *TCase_lcp_timer_start = tcase_create("Unit test for lcp_timer_start"); - TCase *TCase_lcp_zero_restart_count = tcase_create("Unit test for lcp_zero_restart_count"); - TCase *TCase_lcp_timer_stop = tcase_create("Unit test for lcp_timer_stop"); - TCase *TCase_ppp_ctl_packet_size = tcase_create("Unit test for ppp_ctl_packet_size"); - TCase *TCase_ppp_fcs_char = tcase_create("Unit test for ppp_fcs_char"); - TCase *TCase_ppp_fcs_continue = tcase_create("Unit test for ppp_fcs_continue"); - TCase *TCase_ppp_fcs_finish = tcase_create("Unit test for ppp_fcs_finish"); - TCase *TCase_ppp_fcs_start = tcase_create("Unit test for ppp_fcs_start"); - TCase *TCase_ppp_fcs_verify = tcase_create("Unit test for ppp_fcs_verify"); - TCase *TCase_pico_ppp_ctl_send = tcase_create("Unit test for pico_ppp_ctl_send"); - TCase *TCase_pico_ppp_send = tcase_create("Unit test for pico_ppp_send"); - TCase *TCase_ppp_modem_start_timer = tcase_create("Unit test for ppp_modem_start_timer"); - TCase *TCase_ppp_modem_send_reset = tcase_create("Unit test for ppp_modem_send_reset"); - TCase *TCase_ppp_modem_send_echo = tcase_create("Unit test for ppp_modem_send_echo"); - TCase *TCase_ppp_modem_send_creg = tcase_create("Unit test for ppp_modem_send_creg"); - TCase *TCase_ppp_modem_send_cgreg = tcase_create("Unit test for ppp_modem_send_cgreg"); - TCase *TCase_ppp_modem_send_cgdcont = tcase_create("Unit test for ppp_modem_send_cgdcont"); - TCase *TCase_ppp_modem_send_cgatt = tcase_create("Unit test for ppp_modem_send_cgatt"); - TCase *TCase_ppp_modem_send_dial = tcase_create("Unit test for ppp_modem_send_dial"); - TCase *TCase_ppp_modem_connected = tcase_create("Unit test for ppp_modem_connected"); - TCase *TCase_ppp_modem_disconnected = tcase_create("Unit test for ppp_modem_disconnected"); - TCase *TCase_ppp_modem_recv = tcase_create("Unit test for ppp_modem_recv"); - TCase *TCase_lcp_send_configure_request = tcase_create("Unit test for lcp_send_configure_request"); - TCase *TCase_lcp_optflags = tcase_create("Unit test for lcp_optflags"); - TCase *TCase_lcp_send_configure_ack = tcase_create("Unit test for lcp_send_configure_ack"); - TCase *TCase_lcp_send_terminate_request = tcase_create("Unit test for lcp_send_terminate_request"); - TCase *TCase_lcp_send_terminate_ack = tcase_create("Unit test for lcp_send_terminate_ack"); - TCase *TCase_lcp_send_configure_nack = tcase_create("Unit test for lcp_send_configure_nack"); - TCase *TCase_lcp_process_in = tcase_create("Unit test for lcp_process_in"); - TCase *TCase_pap_process_in = tcase_create("Unit test for pap_process_in"); - TCase *TCase_chap_process_in = tcase_create("Unit test for chap_process_in"); - TCase *TCase_ipcp_ack = tcase_create("Unit test for ipcp_ack"); - TCase *TCase_uint32_t = tcase_create("Unit test for uint32_t"); - TCase *TCase_ipcp_request_add_address = tcase_create("Unit test for ipcp_request_add_address"); - TCase *TCase_ipcp_request_fill = tcase_create("Unit test for ipcp_request_fill"); - TCase *TCase_ipcp_send_req = tcase_create("Unit test for ipcp_send_req"); - TCase *TCase_ipcp_reject_vj = tcase_create("Unit test for ipcp_reject_vj"); - TCase *TCase_ppp_ipv4_conf = tcase_create("Unit test for ppp_ipv4_conf"); - TCase *TCase_ipcp_process_in = tcase_create("Unit test for ipcp_process_in"); - TCase *TCase_ipcp6_process_in = tcase_create("Unit test for ipcp6_process_in"); - TCase *TCase_ppp_process_packet_payload = tcase_create("Unit test for ppp_process_packet_payload"); - TCase *TCase_ppp_process_packet = tcase_create("Unit test for ppp_process_packet"); - TCase *TCase_ppp_recv_data = tcase_create("Unit test for ppp_recv_data"); - TCase *TCase_lcp_this_layer_up = tcase_create("Unit test for lcp_this_layer_up"); - TCase *TCase_lcp_this_layer_down = tcase_create("Unit test for lcp_this_layer_down"); - TCase *TCase_lcp_this_layer_started = tcase_create("Unit test for lcp_this_layer_started"); - TCase *TCase_lcp_this_layer_finished = tcase_create("Unit test for lcp_this_layer_finished"); - TCase *TCase_lcp_initialize_restart_count = tcase_create("Unit test for lcp_initialize_restart_count"); - TCase *TCase_lcp_send_code_reject = tcase_create("Unit test for lcp_send_code_reject"); - TCase *TCase_lcp_send_echo_reply = tcase_create("Unit test for lcp_send_echo_reply"); - TCase *TCase_auth = tcase_create("Unit test for auth"); - TCase *TCase_deauth = tcase_create("Unit test for deauth"); - TCase *TCase_auth_req = tcase_create("Unit test for auth_req"); - TCase *TCase_auth_rsp = tcase_create("Unit test for auth_rsp"); - TCase *TCase_auth_start_timer = tcase_create("Unit test for auth_start_timer"); - TCase *TCase_ipcp_send_ack = tcase_create("Unit test for ipcp_send_ack"); - TCase *TCase_ipcp_send_nack = tcase_create("Unit test for ipcp_send_nack"); - TCase *TCase_ipcp_bring_up = tcase_create("Unit test for ipcp_bring_up"); - TCase *TCase_ipcp_bring_down = tcase_create("Unit test for ipcp_bring_down"); - TCase *TCase_ipcp_start_timer = tcase_create("Unit test for ipcp_start_timer"); - TCase *TCase_pico_ppp_poll = tcase_create("Unit test for pico_ppp_poll"); - TCase *TCase_pico_ppp_link_state = tcase_create("Unit test for pico_ppp_link_state"); - TCase *TCase_check_to_modem = tcase_create("Unit test for check_to_modem"); - TCase *TCase_check_to_lcp = tcase_create("Unit test for check_to_lcp"); - TCase *TCase_check_to_auth = tcase_create("Unit test for check_to_auth"); - TCase *TCase_check_to_ipcp = tcase_create("Unit test for check_to_ipcp"); - TCase *TCase_pico_ppp_tick = tcase_create("Unit test for pico_ppp_tick"); - - - tcase_add_test(TCase_ppp_serial_send_escape, tc_ppp_serial_send_escape); - suite_add_tcase(s, TCase_ppp_serial_send_escape); - tcase_add_test(TCase_lcp_timer_start, tc_lcp_timer_start); - suite_add_tcase(s, TCase_lcp_timer_start); - tcase_add_test(TCase_lcp_zero_restart_count, tc_lcp_zero_restart_count); - suite_add_tcase(s, TCase_lcp_zero_restart_count); - tcase_add_test(TCase_lcp_timer_stop, tc_lcp_timer_stop); - suite_add_tcase(s, TCase_lcp_timer_stop); - tcase_add_test(TCase_ppp_ctl_packet_size, tc_ppp_ctl_packet_size); - suite_add_tcase(s, TCase_ppp_ctl_packet_size); - tcase_add_test(TCase_ppp_fcs_char, tc_ppp_fcs_char); - suite_add_tcase(s, TCase_ppp_fcs_char); - tcase_add_test(TCase_ppp_fcs_continue, tc_ppp_fcs_continue); - suite_add_tcase(s, TCase_ppp_fcs_continue); - tcase_add_test(TCase_ppp_fcs_finish, tc_ppp_fcs_finish); - suite_add_tcase(s, TCase_ppp_fcs_finish); - tcase_add_test(TCase_ppp_fcs_start, tc_ppp_fcs_start); - suite_add_tcase(s, TCase_ppp_fcs_start); - tcase_add_test(TCase_ppp_fcs_verify, tc_ppp_fcs_verify); - suite_add_tcase(s, TCase_ppp_fcs_verify); - tcase_add_test(TCase_pico_ppp_ctl_send, tc_pico_ppp_ctl_send); - suite_add_tcase(s, TCase_pico_ppp_ctl_send); - tcase_add_test(TCase_pico_ppp_send, tc_pico_ppp_send); - suite_add_tcase(s, TCase_pico_ppp_send); - tcase_add_test(TCase_ppp_modem_start_timer, tc_ppp_modem_start_timer); - suite_add_tcase(s, TCase_ppp_modem_start_timer); - tcase_add_test(TCase_ppp_modem_send_reset, tc_ppp_modem_send_reset); - suite_add_tcase(s, TCase_ppp_modem_send_reset); - tcase_add_test(TCase_ppp_modem_send_echo, tc_ppp_modem_send_echo); - suite_add_tcase(s, TCase_ppp_modem_send_echo); - tcase_add_test(TCase_ppp_modem_send_creg, tc_ppp_modem_send_creg); - suite_add_tcase(s, TCase_ppp_modem_send_creg); - tcase_add_test(TCase_ppp_modem_send_cgreg, tc_ppp_modem_send_cgreg); - suite_add_tcase(s, TCase_ppp_modem_send_cgreg); - tcase_add_test(TCase_ppp_modem_send_cgdcont, tc_ppp_modem_send_cgdcont); - suite_add_tcase(s, TCase_ppp_modem_send_cgdcont); - tcase_add_test(TCase_ppp_modem_send_cgatt, tc_ppp_modem_send_cgatt); - suite_add_tcase(s, TCase_ppp_modem_send_cgatt); - tcase_add_test(TCase_ppp_modem_send_dial, tc_ppp_modem_send_dial); - suite_add_tcase(s, TCase_ppp_modem_send_dial); - tcase_add_test(TCase_ppp_modem_connected, tc_ppp_modem_connected); - suite_add_tcase(s, TCase_ppp_modem_connected); - tcase_add_test(TCase_ppp_modem_disconnected, tc_ppp_modem_disconnected); - suite_add_tcase(s, TCase_ppp_modem_disconnected); - tcase_add_test(TCase_ppp_modem_recv, tc_ppp_modem_recv); - suite_add_tcase(s, TCase_ppp_modem_recv); - tcase_add_test(TCase_lcp_send_configure_request, tc_lcp_send_configure_request); - suite_add_tcase(s, TCase_lcp_send_configure_request); - tcase_add_test(TCase_lcp_optflags, tc_lcp_optflags); - suite_add_tcase(s, TCase_lcp_optflags); - tcase_add_test(TCase_lcp_send_configure_ack, tc_lcp_send_configure_ack); - suite_add_tcase(s, TCase_lcp_send_configure_ack); - tcase_add_test(TCase_lcp_send_terminate_request, tc_lcp_send_terminate_request); - suite_add_tcase(s, TCase_lcp_send_terminate_request); - tcase_add_test(TCase_lcp_send_terminate_ack, tc_lcp_send_terminate_ack); - suite_add_tcase(s, TCase_lcp_send_terminate_ack); - tcase_add_test(TCase_lcp_send_configure_nack, tc_lcp_send_configure_nack); - suite_add_tcase(s, TCase_lcp_send_configure_nack); - tcase_add_test(TCase_lcp_process_in, tc_lcp_process_in); - suite_add_tcase(s, TCase_lcp_process_in); - tcase_add_test(TCase_pap_process_in, tc_pap_process_in); - suite_add_tcase(s, TCase_pap_process_in); - tcase_add_test(TCase_chap_process_in, tc_chap_process_in); - suite_add_tcase(s, TCase_chap_process_in); - tcase_add_test(TCase_ipcp_ack, tc_ipcp_ack); - suite_add_tcase(s, TCase_ipcp_ack); - tcase_add_test(TCase_uint32_t, tc_uint32_t); - suite_add_tcase(s, TCase_uint32_t); - tcase_add_test(TCase_ipcp_request_add_address, tc_ipcp_request_add_address); - suite_add_tcase(s, TCase_ipcp_request_add_address); - tcase_add_test(TCase_ipcp_request_fill, tc_ipcp_request_fill); - suite_add_tcase(s, TCase_ipcp_request_fill); - tcase_add_test(TCase_ipcp_send_req, tc_ipcp_send_req); - suite_add_tcase(s, TCase_ipcp_send_req); - tcase_add_test(TCase_ipcp_reject_vj, tc_ipcp_reject_vj); - suite_add_tcase(s, TCase_ipcp_reject_vj); - tcase_add_test(TCase_ppp_ipv4_conf, tc_ppp_ipv4_conf); - suite_add_tcase(s, TCase_ppp_ipv4_conf); - tcase_add_test(TCase_ipcp_process_in, tc_ipcp_process_in); - suite_add_tcase(s, TCase_ipcp_process_in); - tcase_add_test(TCase_ipcp6_process_in, tc_ipcp6_process_in); - suite_add_tcase(s, TCase_ipcp6_process_in); - tcase_add_test(TCase_ppp_process_packet_payload, tc_ppp_process_packet_payload); - suite_add_tcase(s, TCase_ppp_process_packet_payload); - tcase_add_test(TCase_ppp_process_packet, tc_ppp_process_packet); - suite_add_tcase(s, TCase_ppp_process_packet); - tcase_add_test(TCase_ppp_recv_data, tc_ppp_recv_data); - suite_add_tcase(s, TCase_ppp_recv_data); - tcase_add_test(TCase_lcp_this_layer_up, tc_lcp_this_layer_up); - suite_add_tcase(s, TCase_lcp_this_layer_up); - tcase_add_test(TCase_lcp_this_layer_down, tc_lcp_this_layer_down); - suite_add_tcase(s, TCase_lcp_this_layer_down); - tcase_add_test(TCase_lcp_this_layer_started, tc_lcp_this_layer_started); - suite_add_tcase(s, TCase_lcp_this_layer_started); - tcase_add_test(TCase_lcp_this_layer_finished, tc_lcp_this_layer_finished); - suite_add_tcase(s, TCase_lcp_this_layer_finished); - tcase_add_test(TCase_lcp_initialize_restart_count, tc_lcp_initialize_restart_count); - suite_add_tcase(s, TCase_lcp_initialize_restart_count); - tcase_add_test(TCase_lcp_send_code_reject, tc_lcp_send_code_reject); - suite_add_tcase(s, TCase_lcp_send_code_reject); - tcase_add_test(TCase_lcp_send_echo_reply, tc_lcp_send_echo_reply); - suite_add_tcase(s, TCase_lcp_send_echo_reply); - tcase_add_test(TCase_auth, tc_auth); - suite_add_tcase(s, TCase_auth); - tcase_add_test(TCase_deauth, tc_deauth); - suite_add_tcase(s, TCase_deauth); - tcase_add_test(TCase_auth_req, tc_auth_req); - suite_add_tcase(s, TCase_auth_req); - tcase_add_test(TCase_auth_rsp, tc_auth_rsp); - suite_add_tcase(s, TCase_auth_rsp); - tcase_add_test(TCase_auth_start_timer, tc_auth_start_timer); - suite_add_tcase(s, TCase_auth_start_timer); - tcase_add_test(TCase_ipcp_send_ack, tc_ipcp_send_ack); - suite_add_tcase(s, TCase_ipcp_send_ack); - tcase_add_test(TCase_ipcp_send_nack, tc_ipcp_send_nack); - suite_add_tcase(s, TCase_ipcp_send_nack); - tcase_add_test(TCase_ipcp_bring_up, tc_ipcp_bring_up); - suite_add_tcase(s, TCase_ipcp_bring_up); - tcase_add_test(TCase_ipcp_bring_down, tc_ipcp_bring_down); - suite_add_tcase(s, TCase_ipcp_bring_down); - tcase_add_test(TCase_ipcp_start_timer, tc_ipcp_start_timer); - suite_add_tcase(s, TCase_ipcp_start_timer); - tcase_add_test(TCase_pico_ppp_poll, tc_pico_ppp_poll); - suite_add_tcase(s, TCase_pico_ppp_poll); - tcase_add_test(TCase_pico_ppp_link_state, tc_pico_ppp_link_state); - suite_add_tcase(s, TCase_pico_ppp_link_state); - tcase_add_test(TCase_check_to_modem, tc_check_to_modem); - suite_add_tcase(s, TCase_check_to_modem); - tcase_add_test(TCase_check_to_lcp, tc_check_to_lcp); - suite_add_tcase(s, TCase_check_to_lcp); - tcase_add_test(TCase_check_to_auth, tc_check_to_auth); - suite_add_tcase(s, TCase_check_to_auth); - tcase_add_test(TCase_check_to_ipcp, tc_check_to_ipcp); - suite_add_tcase(s, TCase_check_to_ipcp); - tcase_add_test(TCase_pico_ppp_tick, tc_pico_ppp_tick); - suite_add_tcase(s, TCase_pico_ppp_tick); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - mock_modem_state = modem_state; - mock_lcp_state = lcp_state; - mock_auth_state = auth_state; - mock_ipcp_state = ipcp_state; - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_dns_client.c b/ext/picotcp/test/unit/modunit_pico_dns_client.c deleted file mode 100644 index 7e3831e..0000000 --- a/ext/picotcp/test/unit/modunit_pico_dns_client.c +++ /dev/null @@ -1,229 +0,0 @@ -#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_udp.h" -#include "modules/pico_dns_client.c" -#include "check.h" - -Suite *pico_suite(void); - -START_TEST(tc_pico_dns_client_callback) -{ - struct pico_socket *s = pico_udp_open(); - s->proto = &pico_proto_udp; - - fail_if(!s); - - /* Test with ERR */ - pico_dns_client_callback(PICO_SOCK_EV_ERR, s); - - /* Test with failing RD */ - pico_dns_client_callback(PICO_SOCK_EV_RD, s); - -} -END_TEST -START_TEST(tc_pico_dns_client_retransmission) -{ - /* TODO: test this: static void pico_dns_client_retransmission(pico_time now, void *arg); */ -} -END_TEST -START_TEST(tc_dns_ns_cmp) -{ - /* TODO: test this: static int dns_ns_cmp(void *ka, void *kb) */ -} -END_TEST -START_TEST(tc_dns_query_cmp) -{ - /* TODO: test this: static int dns_query_cmp(void *ka, void *kb) */ -} -END_TEST -START_TEST(tc_pico_dns_client_del_ns) -{ - /* TODO: test this: static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr) */ -} -END_TEST -START_TEST(tc_pico_dns_ns) -{ - /* TODO: test this: static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr) */ -} -END_TEST -START_TEST(tc_pico_dns_client_del_query) -{ - /* TODO: test this: static int pico_dns_client_del_query(uint16_t id) */ -} -END_TEST -START_TEST(tc_pico_dns_query) -{ - /* TODO: test this: static struct pico_dns_query *pico_dns_client_find_query(uint16_t id) */ -} -END_TEST -START_TEST(tc_pico_dns_client_strlen) -{ - /* TODO: test this: static uint16_t pico_dns_client_strlen(const char *url) */ -} -END_TEST -START_TEST(tc_pico_dns_client_seek) -{ - /* TODO: test this: static char *pico_dns_client_seek(char *ptr) */ -} -END_TEST -START_TEST(tc_pico_dns_client_mirror) -{ - /* TODO: test this: static int8_t pico_dns_client_mirror(char *ptr) */ -} -END_TEST -START_TEST(tc_pico_dns_client_query_prefix) -{ - /* TODO: test this: static int pico_dns_client_query_prefix(struct pico_dns_prefix *pre) */ -} -END_TEST -START_TEST(tc_pico_dns_client_query_suffix) -{ - /* TODO: test this: static int pico_dns_client_query_suffix(struct pico_dns_query_suffix *suf, uint16_t type, uint16_t class) */ -} -END_TEST -START_TEST(tc_pico_dns_client_query_domain) -{ - /* TODO: test this: static int pico_dns_client_query_domain(char *ptr) */ -} -END_TEST -START_TEST(tc_pico_dns_client_answer_domain) -{ - /* TODO: test this: static int pico_dns_client_answer_domain(char *ptr) */ -} -END_TEST -START_TEST(tc_pico_dns_client_check_prefix) -{ - /* TODO: test this: static int pico_dns_client_check_prefix(struct pico_dns_prefix *pre) */ -} -END_TEST -START_TEST(tc_pico_dns_client_check_qsuffix) -{ - /* TODO: test this: static int pico_dns_client_check_qsuffix(struct pico_dns_query_suffix *suf, struct pico_dns_query *q) */ -} -END_TEST -START_TEST(tc_pico_dns_client_check_asuffix) -{ - /* TODO: test this: static int pico_dns_client_check_asuffix(struct pico_dns_answer_suffix *suf, struct pico_dns_query *q) */ -} -END_TEST -START_TEST(tc_pico_dns_client_seek_suffix) -{ - /* TODO: test this: static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_prefix *pre, struct pico_dns_query *q) */ -} -END_TEST -START_TEST(tc_pico_dns_client_send) -{ - /* TODO: test this: static int pico_dns_client_send(struct pico_dns_query *q) */ -} -END_TEST -START_TEST(tc_pico_dns_client_user_callback) -{ - /* TODO: test this: static int pico_dns_client_user_callback(struct pico_dns_answer_suffix *asuffix, struct pico_dns_query *q) */ -} -END_TEST -START_TEST(tc_pico_dns_client_getaddr_init) -{ - /* TODO: test this: static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg) */ -} -END_TEST -START_TEST(tc_pico_dns_ipv6_set_ptr) -{ - /* TODO: test this: static void pico_dns_ipv6_set_ptr(const char *ip, char *dst) */ -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_dns_client_callback = tcase_create("Unit test for pico_dns_client_callback"); - TCase *TCase_pico_dns_client_retransmission = tcase_create("Unit test for pico_dns_client_retransmission"); - TCase *TCase_dns_ns_cmp = tcase_create("Unit test for dns_ns_cmp"); - TCase *TCase_dns_query_cmp = tcase_create("Unit test for dns_query_cmp"); - TCase *TCase_pico_dns_client_del_ns = tcase_create("Unit test for pico_dns_client_del_ns"); - TCase *TCase_pico_dns_ns = tcase_create("Unit test for pico_dns_ns"); - TCase *TCase_pico_dns_client_del_query = tcase_create("Unit test for pico_dns_client_del_query"); - TCase *TCase_pico_dns_query = tcase_create("Unit test for pico_dns_query"); - TCase *TCase_pico_dns_client_strlen = tcase_create("Unit test for pico_dns_client_strlen"); - TCase *TCase_pico_dns_client_seek = tcase_create("Unit test for pico_dns_client_seek"); - TCase *TCase_pico_dns_client_mirror = tcase_create("Unit test for pico_dns_client_mirror"); - TCase *TCase_pico_dns_client_query_prefix = tcase_create("Unit test for pico_dns_client_query_prefix"); - TCase *TCase_pico_dns_client_query_suffix = tcase_create("Unit test for pico_dns_client_query_suffix"); - TCase *TCase_pico_dns_client_query_domain = tcase_create("Unit test for pico_dns_client_query_domain"); - TCase *TCase_pico_dns_client_answer_domain = tcase_create("Unit test for pico_dns_client_answer_domain"); - TCase *TCase_pico_dns_client_check_prefix = tcase_create("Unit test for pico_dns_client_check_prefix"); - TCase *TCase_pico_dns_client_check_qsuffix = tcase_create("Unit test for pico_dns_client_check_qsuffix"); - TCase *TCase_pico_dns_client_check_asuffix = tcase_create("Unit test for pico_dns_client_check_asuffix"); - TCase *TCase_pico_dns_client_seek_suffix = tcase_create("Unit test for pico_dns_client_seek_suffix"); - TCase *TCase_pico_dns_client_send = tcase_create("Unit test for pico_dns_client_send"); - TCase *TCase_pico_dns_client_user_callback = tcase_create("Unit test for pico_dns_client_user_callback"); - TCase *TCase_pico_dns_client_getaddr_init = tcase_create("Unit test for pico_dns_client_getaddr_init"); - TCase *TCase_pico_dns_ipv6_set_ptr = tcase_create("Unit test for pico_dns_ipv6_set_ptr"); - - - tcase_add_test(TCase_pico_dns_client_callback, tc_pico_dns_client_callback); - suite_add_tcase(s, TCase_pico_dns_client_callback); - tcase_add_test(TCase_pico_dns_client_retransmission, tc_pico_dns_client_retransmission); - suite_add_tcase(s, TCase_pico_dns_client_retransmission); - tcase_add_test(TCase_dns_ns_cmp, tc_dns_ns_cmp); - suite_add_tcase(s, TCase_dns_ns_cmp); - tcase_add_test(TCase_dns_query_cmp, tc_dns_query_cmp); - suite_add_tcase(s, TCase_dns_query_cmp); - tcase_add_test(TCase_pico_dns_client_del_ns, tc_pico_dns_client_del_ns); - suite_add_tcase(s, TCase_pico_dns_client_del_ns); - tcase_add_test(TCase_pico_dns_ns, tc_pico_dns_ns); - suite_add_tcase(s, TCase_pico_dns_ns); - tcase_add_test(TCase_pico_dns_client_del_query, tc_pico_dns_client_del_query); - suite_add_tcase(s, TCase_pico_dns_client_del_query); - tcase_add_test(TCase_pico_dns_query, tc_pico_dns_query); - suite_add_tcase(s, TCase_pico_dns_query); - tcase_add_test(TCase_pico_dns_client_strlen, tc_pico_dns_client_strlen); - suite_add_tcase(s, TCase_pico_dns_client_strlen); - tcase_add_test(TCase_pico_dns_client_seek, tc_pico_dns_client_seek); - suite_add_tcase(s, TCase_pico_dns_client_seek); - tcase_add_test(TCase_pico_dns_client_mirror, tc_pico_dns_client_mirror); - suite_add_tcase(s, TCase_pico_dns_client_mirror); - tcase_add_test(TCase_pico_dns_client_query_prefix, tc_pico_dns_client_query_prefix); - suite_add_tcase(s, TCase_pico_dns_client_query_prefix); - tcase_add_test(TCase_pico_dns_client_query_suffix, tc_pico_dns_client_query_suffix); - suite_add_tcase(s, TCase_pico_dns_client_query_suffix); - tcase_add_test(TCase_pico_dns_client_query_domain, tc_pico_dns_client_query_domain); - suite_add_tcase(s, TCase_pico_dns_client_query_domain); - tcase_add_test(TCase_pico_dns_client_answer_domain, tc_pico_dns_client_answer_domain); - suite_add_tcase(s, TCase_pico_dns_client_answer_domain); - tcase_add_test(TCase_pico_dns_client_check_prefix, tc_pico_dns_client_check_prefix); - suite_add_tcase(s, TCase_pico_dns_client_check_prefix); - tcase_add_test(TCase_pico_dns_client_check_qsuffix, tc_pico_dns_client_check_qsuffix); - suite_add_tcase(s, TCase_pico_dns_client_check_qsuffix); - tcase_add_test(TCase_pico_dns_client_check_asuffix, tc_pico_dns_client_check_asuffix); - suite_add_tcase(s, TCase_pico_dns_client_check_asuffix); - tcase_add_test(TCase_pico_dns_client_seek_suffix, tc_pico_dns_client_seek_suffix); - suite_add_tcase(s, TCase_pico_dns_client_seek_suffix); - tcase_add_test(TCase_pico_dns_client_send, tc_pico_dns_client_send); - suite_add_tcase(s, TCase_pico_dns_client_send); - tcase_add_test(TCase_pico_dns_client_user_callback, tc_pico_dns_client_user_callback); - suite_add_tcase(s, TCase_pico_dns_client_user_callback); - tcase_add_test(TCase_pico_dns_client_getaddr_init, tc_pico_dns_client_getaddr_init); - suite_add_tcase(s, TCase_pico_dns_client_getaddr_init); - tcase_add_test(TCase_pico_dns_ipv6_set_ptr, tc_pico_dns_ipv6_set_ptr); - suite_add_tcase(s, TCase_pico_dns_ipv6_set_ptr); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_dns_common.c b/ext/picotcp/test/unit/modunit_pico_dns_common.c deleted file mode 100644 index b172796..0000000 --- a/ext/picotcp/test/unit/modunit_pico_dns_common.c +++ /dev/null @@ -1,1446 +0,0 @@ -#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_common.h" -#include "pico_tree.h" -#include "modules/pico_dns_common.c" -#include "check.h" - -Suite *pico_suite(void); - -START_TEST(tc_dns_rdata_cmp) /* MARK: dns_rdata_cmp */ -{ - uint8_t rdata1[10] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 - }; - uint8_t rdata2[10] = { - 1, 2, 3, 3, 5, 6, 7, 8, 9, 10 - }; - uint8_t rdata3[1] = { - 2 - }; - uint8_t rdata4[1] = { - 1 - }; - uint8_t rdata5[11] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9 - }; - uint8_t rdata6[12] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 - }; - - uint8_t rdata7[5] = { - 72, 69, 76, 76, 79 - }; - - uint8_t rdata8[5] = { - 104, 101, 108, 108, 111 - }; - - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Check equal data and size */ - ret = pico_dns_rdata_cmp(rdata1, rdata1, 10, 10, 0); - fail_unless(!ret, "dns_rdata_cmp failed with equal data and size, case-sensitive!\n"); - - /* Check smaller data and equal size */ - ret = pico_dns_rdata_cmp(rdata1, rdata2, 10, 10, 0); - fail_unless(ret > 0, "dns_rdata_cmp failed with smaller data and equal size, case-sensitive!\n"); - - /* Check larger data and smaller size */ - ret = pico_dns_rdata_cmp(rdata1, rdata3, 10, 1, 0); - fail_unless(ret < 0, "dns_rdata_cmp failed with larger data and smaller size, case-sensitive!\n"); - - /* Check equal data and smaller size */ - ret = pico_dns_rdata_cmp(rdata1, rdata4, 10, 1, 0); - fail_unless(ret > 0, "dns_rdata_cmp failed with equal data and smaller size, case-sensitive!\n"); - - /* Check smaller data and larger size */ - ret = pico_dns_rdata_cmp(rdata1, rdata5, 10, 11, 0); - fail_unless(ret < 0, "dns_rdata_cmp failed with equal data and larger size, case-sensitive!\n"); - - /* Check larger data and larger size */ - ret = pico_dns_rdata_cmp(rdata1, rdata6, 10, 12, 0); - fail_unless(ret < 0, "dns_rdata_cmp failed with larger data and larger size, case-sensitive!\n"); - - /* Check for tolower effect */ - ret = pico_dns_rdata_cmp(rdata7, rdata8, 5, 5, 0); - fail_unless(ret < 0, "dns_rdata_cmp failed with check for tolower effect, case-sensitive!\n"); - - /* now check with case-insensitive */ - - /* Check equal data and size */ - ret = pico_dns_rdata_cmp(rdata1, rdata1, 10, 10, 1); - fail_unless(!ret, "dns_rdata_cmp failed with equal data and size, case-insensitive!\n"); - - /* Check smaller data and equal size */ - ret = pico_dns_rdata_cmp(rdata1, rdata2, 10, 10, 1); - fail_unless(ret > 0, "dns_rdata_cmp failed with smaller data and equal size, case-insensitive!\n"); - - /* Check larger data and smaller size */ - ret = pico_dns_rdata_cmp(rdata1, rdata3, 10, 1, 1); - fail_unless(ret < 0, "dns_rdata_cmp failed with larger data and smaller size, case-insensitive!\n"); - - /* Check equal data and smaller size */ - ret = pico_dns_rdata_cmp(rdata1, rdata4, 10, 1, 1); - fail_unless(ret > 0, "dns_rdata_cmp failed with equal data and smaller size, case-insensitive!\n"); - - /* Check smaller data and larger size */ - ret = pico_dns_rdata_cmp(rdata1, rdata5, 10, 11, 1); - fail_unless(ret < 0, "dns_rdata_cmp failed with equal data and larger size, case-insensitive!\n"); - - /* Check larger data and larger size */ - ret = pico_dns_rdata_cmp(rdata1, rdata6, 10, 12, 1); - fail_unless(ret < 0, "dns_rdata_cmp failed with larger data and larger size, case-insensitive!\n"); - - /* Check for tolower effect */ - ret = pico_dns_rdata_cmp(rdata7, rdata8, 5, 5, 1); - fail_unless(ret == 0, "dns_rdata_cmp failed with check for tolower effect, case-insensitive!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_question_cmp) /* MARK: dns_question_cmp */ -{ - struct pico_dns_question *a = NULL, *b = NULL; - const char *url1 = "host (2).local"; - const char *url3 = "host.local"; - const char *url2 = "192.168.2.1"; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - a = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Question A could not be created!\n"); - b = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Question B could not be created!\n"); - - ret = pico_dns_question_cmp((void *)a, (void *)b); - fail_unless(ret > 0, "Question is lexicographically smaller"); - pico_dns_question_delete((void **)&a); - pico_dns_question_delete((void **)&b); - - a = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_PTR, - PICO_DNS_CLASS_IN, 1); - fail_if(!a, "Question A could not be created!\n"); - b = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_PTR, - PICO_DNS_CLASS_IN, 1); - fail_if(!b, "Question B could not be created!\n"); - - ret = pico_dns_question_cmp((void *)a, (void *)b); - fail_unless(!ret, "Question A and B should be equal!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_qtree_insert) /* MARK: dns_qtree_insert*/ -{ - const char *url = "host.local"; - const char *url2 = "host (2).local"; - const char *url3 = "host (3).local"; - struct pico_dns_question *a = NULL, *b = NULL, *c = NULL; - uint16_t qlen = 0; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_DNS_QTREE_DECLARE(qtree2); - - printf("*********************** starting %s * \n", __func__); - - a = pico_dns_question_create(url, &qlen, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a || !(a->qname) || !(a->qsuffix), "Could not create question A!\n"); - b = pico_dns_question_create(url2, &qlen, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b || !(b->qname) || !(b->qsuffix), "Coud not create question B!\n"); - - pico_tree_insert(&qtree, a); - fail_unless(pico_tree_count(&qtree) == 1, - "pico_tree_insert failed with tree 1 question A!\n"); - - pico_tree_insert(&qtree, b); - fail_unless(2 == pico_tree_count(&qtree), - "pico_tree_insert failed with tree 1 question B!\n"); - - PICO_DNS_QTREE_DESTROY(&qtree); - fail_unless(0 == pico_tree_count(&qtree), - "Question tree not properly destroyed!\n"); - c = pico_dns_question_create(url3, &qlen, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!c || !(c->qname) || !(c->qsuffix), "Coud not create question B!\n"); - pico_tree_insert(&qtree2, c); - fail_unless(1 == pico_tree_count(&qtree2), - "pico_tree_insert failed with tree 2 question B!\n"); - PICO_DNS_QTREE_DESTROY(&qtree2); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_record_cmp) /* MARK: dns_record_cmp */ -{ - struct pico_dns_record *a = NULL; - struct pico_dns_record *b = NULL; - const char *url1 = "foo.local"; - const char *url3 = "a.local"; - struct pico_ip4 rdata = { - 0 - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create test records */ - a = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Record A could not be created!\n"); - b = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Record B could not be created!\n"); - - /* Try to compare equal records */ - ret = pico_dns_record_cmp((void *) a, (void *) b); - fail_unless(!ret, "dns_record_cmp failed with equal records - %d!\n", ret); - pico_dns_record_delete((void **)&a); - pico_dns_record_delete((void **)&b); - - /* Create different test records */ - a = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Record A could not be created!\n"); - b = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Record B could not be created!\n"); - - /* Try to compare records with equal rname but different type */ - ret = pico_dns_record_cmp((void *) a, (void *) b); - fail_unless(ret > 0, "dns_record_cmp failed with same name, different types!\n"); - pico_dns_record_delete((void **)&a); - pico_dns_record_delete((void **)&b); - - /* Create different test records */ - a = pico_dns_record_create(url3, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Record A could not be created!\n"); - b = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Record B could not be created!\n"); - - /* Try to compare records with different rname but equal type */ - ret = pico_dns_record_cmp((void *) a, (void *) b); - fail_unless(ret < 0, "mdns_cmp failed with different name, same types!\n"); - pico_dns_record_delete((void **)&a); - pico_dns_record_delete((void **)&b); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_rtree_insert) /* MARK: dns_rtree_insert*/ -{ - PICO_DNS_RTREE_DECLARE(rtree); - PICO_DNS_RTREE_DECLARE(rtree2); - struct pico_dns_record *a = NULL; - struct pico_dns_record *b = NULL, *c = NULL; - const char *url1 = "foo.local"; - struct pico_ip4 rdata = { - 0 - }; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create test records */ - a = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Record A could not be created!\n"); - b = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Record B could not be created!\n"); - - pico_tree_insert(&rtree, a); - pico_tree_insert(&rtree, b); - - PICO_DNS_RTREE_DESTROY(&rtree); - fail_unless(pico_tree_count(&rtree) == 0, - "Record tree not properly destroyed!\n"); - - c = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!c, "Record C could not be created!\n"); - pico_tree_insert(&rtree2, c); - - PICO_DNS_RTREE_DESTROY(&rtree2); - fail_unless(pico_tree_count(&rtree2) == 0, - "Record tree not properly destroyed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_record_cmp_name_type) /* MARK: dns_record_cmp_name_type */ -{ - struct pico_dns_record *a = NULL; - struct pico_dns_record *b = NULL; - const char *url1 = "foo.local"; - const char *url3 = "a.local"; - struct pico_ip4 rdata = { - 0 - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create different test records */ - a = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Record A could not be created!\n"); - b = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Record B could not be created!\n"); - - /* Try to compare records with equal rname but different type */ - ret = pico_dns_record_cmp_name_type((void *) a, (void *) b); - fail_unless(ret > 0, "dns_record_cmp failed with same name, different types!\n"); - pico_dns_record_delete((void **)&a); - pico_dns_record_delete((void **)&b); - - /* Create exactly the same test records */ - a = pico_dns_record_create(url3, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "Record A could not be created!\n"); - b = pico_dns_record_create(url3, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "Record B could not be created!\n"); - - /* Try to compare records with different rname but equal type */ - ret = pico_dns_record_cmp_name_type((void *) a, (void *) b); - fail_unless(!ret, "dns_record_cmp_name_type failed with same names, same types!\n"); - pico_dns_record_delete((void **)&a); - pico_dns_record_delete((void **)&b); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_fill_packet_header) /* MARK: dns_fill_packet_header */ -{ - struct pico_dns_header *header = NULL; - uint8_t answer_buf[12] = { - 0x00, 0x00, - 0x85, 0x00, - 0x00, 0x00, - 0x00, 0x01, - 0x00, 0x01, - 0x00, 0x01 - }; - uint8_t query_buf[12] = { - 0x00, 0x00, - 0x01, 0x00, - 0x00, 0x01, - 0x00, 0x01, - 0x00, 0x01, - 0x00, 0x01 - }; - int i = 0; - - printf("*********************** starting %s * \n", __func__); - - header = (struct pico_dns_header *) - PICO_ZALLOC(sizeof(struct pico_dns_header)); - - fail_if(NULL == header, "Not enough space!\n"); - - /* Create a query header */ - pico_dns_fill_packet_header(header, 1, 1, 1, 1); - - for (i = 0; i < 12; i++) - printf("### %02x :: %02x\n", ((uint8_t*)header)[i], query_buf[i]); - fail_unless(0 == memcmp((void *)header, (void *)query_buf, 12), - "Comparing query header failed!\n"); - - /* Create a answer header */ - pico_dns_fill_packet_header(header, 0, 1, 1, 1); - - fail_unless(0 == memcmp((void *)header, (void *)answer_buf, 12), - "Comparing answer header failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_fill_packet_rr_section) /* MARK: dns_fill_packet_rr_section */ -{ - printf("*********************** starting %s * \n", __func__); - - /* TODO: Insert test here */ - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_fill_packet_rr_sections) /* MARK: dns_fill_packet_rr_sections */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_DNS_RTREE_DECLARE(antree); - PICO_DNS_RTREE_DECLARE(nstree); - PICO_DNS_RTREE_DECLARE(artree); - struct pico_dns_record *record = NULL; - const char *rname = "picotcp.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint8_t cmp_buf[39] = { - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00u, 0x78u, - 0x00u, 0x04u, - 10u, 10u, 0u, 1u - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create a new A record */ - record = pico_dns_record_create(rname, rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!record, "dns_record_create failed!\n"); - - /* Add the record to a tree */ - pico_tree_insert(&antree, record); - - /* Try to fill the rr sections with packet as a NULL-pointer */ - ret = pico_dns_fill_packet_rr_sections(packet, &qtree, &antree, - &nstree, &artree); - fail_unless(ret, "Checking of params failed!\n"); - - len = (uint16_t)sizeof(struct pico_dns_header); - pico_tree_size(&qtree, &len, &pico_dns_question_size); - pico_tree_size(&antree, &len, &pico_dns_record_size); - pico_tree_size(&nstree, &len, &pico_dns_record_size); - pico_tree_size(&artree, &len, &pico_dns_record_size); - printf("Packet len: %d\n", len); - - /* Allocate the packet with the right size */ - packet = (pico_dns_packet *)PICO_ZALLOC((size_t)len); - fail_if(NULL == packet, "Allocating packet failed!\n"); - fail_if(pico_dns_fill_packet_rr_sections(packet, &qtree, &antree, &nstree, - &artree), - "Filling of rr sections failed!\n"); - - fail_unless(memcmp((void *)packet, (void *)cmp_buf, 39) == 0, - "Filling of rr sections went wrong!\n"); - PICO_FREE(packet); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_fill_packet_question_section) /* MARK: dns_fill_packet_question_section */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - struct pico_dns_question *a = NULL, *b = NULL; - const char *qurl = "picotcp.com"; - uint8_t cmp_buf[45] = { - 0x00u, 0x00u, /* 2 */ - 0x00u, 0x00u, /* 2 */ - 0x00u, 0x00u, /* 2 */ - 0x00u, 0x00u, /* 2 */ - 0x00u, 0x00u, /* 2 */ - 0x00u, 0x00u, /* 2 //12 */ - 0x06u, 'g', 'o', 'o', 'g', 'l', 'e', /* 7 */ - 0x03u, 'c', 'o', 'm', /* 4 */ - 0x00u, /* 1 //12 */ - 0x00u, 0x01u, - 0x00u, 0x01u, /* 4 */ - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', /* 8 */ - 0x03u, 'c', 'o', 'm', /* 4 */ - 0x00u, /* 1 //13 */ - 0x00u, 0x01u, - 0x00u, 0x01u - }; /* 4 */ - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create DNS questions and a vector of them */ - a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(NULL == a, "dns_question_create failed!\n"); - b = pico_dns_question_create("google.com", &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(NULL == b, "dns_question_create failed!\n"); - - pico_tree_insert(&qtree, a); - pico_tree_insert(&qtree, b); - - /* Determine the length of the packet and provide space */ - len = (uint16_t)sizeof(struct pico_dns_header); - pico_tree_size(&qtree, &len, &pico_dns_question_size); - printf("Packet len: %d - 45\n", len); - packet = (pico_dns_packet *)PICO_ZALLOC((size_t)len); - - fail_if(NULL == packet, "Allocating packet failed!\n"); - fail_if(pico_dns_fill_packet_question_section(packet, &qtree), - "Filling of rr sections failed!\n"); - - fail_unless(memcmp((void *)packet, (void *)cmp_buf, 45) == 0, - "Filling of question sesction went wrong!\n"); - PICO_FREE(packet); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_packet_compress_find_ptr) /* MARK: dns_packet_compress_find_ptr */ -{ - uint8_t data[] = "abcdef\5local\0abcdef\4test\5local"; - uint8_t *name = (uint8_t *)(data + 24); - uint16_t len = 31; - uint8_t *ptr = NULL; - - printf("*********************** starting %s * \n", __func__); - - ptr = pico_dns_packet_compress_find_ptr(name, data, len); - fail_unless(ptr == (data + 6), "Finding compression ptr failed %p - %p!\n", ptr, - data + 6); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_packet_compress_name) /* MARK: dns_packet_compress_name */ -{ - uint8_t buf[46] = { - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u - }; - - uint8_t *name = buf + 29u; - uint16_t len = 46; - int ret = 0; - printf("*********************** starting %s * \n", __func__); - - ret = pico_dns_packet_compress_name(name, buf, &len); - fail_unless(ret == 0, "dns_packet_compress_name returned error!\n"); - fail_unless(len == (46 - 11), "packet_compress_name return wrong length!\n"); - fail_unless(memcmp(name, "\xc0\x0c", 2) == 0, "packet_compress_name failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_packet_compress) /* MARK: dns_packet_compress */ -{ - uint8_t buf[83] = { - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x01u, - 0x00u, 0x00u, - 0x00u, 0x02u, - 0x00u, 0x00u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00, 0x0A, - 0x00u, 0x04u, - 0x0Au, 0x0Au, 0x0A, 0x0A, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00, 0x0A, - 0x00u, 0x04u, - 0x0Au, 0x0Au, 0x0A, 0x0A - }; - uint8_t cmp_buf[61] = { - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x01u, - 0x00u, 0x00u, - 0x00u, 0x02u, - 0x00u, 0x00u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0xC0u, 0x0Cu, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00, 0x0A, - 0x00u, 0x04u, - 0x0Au, 0x0Au, 0x0A, 0x0A, - 0xC0u, 0x0Cu, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00, 0x0A, - 0x00u, 0x04u, - 0x0Au, 0x0Au, 0x0A, 0x0A - }; - pico_dns_packet *packet = (pico_dns_packet *)buf; - uint16_t len = 83; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - ret = pico_dns_packet_compress(packet, &len); - - fail_unless(ret == 0, "dns_packet_compress returned error!\n"); - fail_unless(len == (83 - 22), "packet_compress returned length %u!\n", len); - fail_unless(memcmp(packet, cmp_buf, 61) == 0, "packet_compress_name failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_question_fill_qsuffix) /* MARK: dns_question_fill_suffix */ -{ - struct pico_dns_question_suffix suffix; - printf("*********************** starting %s * \n", __func__); - - pico_dns_question_fill_suffix(&suffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); - - fail_unless((suffix.qtype == short_be(PICO_DNS_TYPE_A)) && - (suffix.qclass == short_be(PICO_DNS_CLASS_IN)), - "Filling qsuffix failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_question_delete) /* MARK: dns_question_delete */ -{ - const char *qurl = "picotcp.com"; - uint16_t len = 0; - int ret = 0; - struct pico_dns_question *a = pico_dns_question_create(qurl, &len, - PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, - 0); - printf("*********************** starting %s * \n", __func__); - - ret = pico_dns_question_delete((void **)&a); - - fail_unless(ret == 0, "dns_question_delete returned error!\n"); - fail_unless(a == NULL, "dns_question_delete failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_question_create) /* MARK: dns_quesiton_create */ -{ - const char *qurl = "picotcp.com"; - const char *qurl2 = "1.2.3.4"; - const char *qurl3 = "2001:0db8:0000:0000:0000:0000:0000:0000"; - char buf[13] = { - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03u, 'c', 'o', 'm', - 0x00u - }; - char buf2[22] = { - 0x01u, '4', - 0x01u, '3', - 0x01u, '2', - 0x01u, '1', - 0x07u, 'i', 'n', '-', 'a', 'd', 'd', 'r', - 0x04u, 'a', 'r', 'p', 'a', - 0x00u - }; - char buf3[74] = { - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '8', 0x01u, 'b', 0x01u, 'd', 0x01u, '0', - 0x01u, '1', 0x01u, '0', 0x01u, '0', 0x01u, '2', - 0x03u, 'I', 'P', '6', - 0x04u, 'A', 'R', 'P', 'A', - 0x00u - }; - uint16_t len = 0; - struct pico_dns_question *a = NULL; - - printf("*********************** starting %s * \n", __func__); - - /* First, plain A record */ - a = pico_dns_question_create(qurl, &len, - PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, - 0); - fail_if(a == NULL, "dns_question_created returned NULL!\n"); - fail_unless(strcmp(a->qname, buf) == 0, "url not converted correctly!\n"); - fail_unless(short_be(a->qsuffix->qtype) == PICO_DNS_TYPE_A, - "qtype not properly set!\n"); - fail_unless(short_be(a->qsuffix->qclass) == PICO_DNS_CLASS_IN, - "qclass not properly set!\n"); - pico_dns_question_delete((void **)&a); - - /* Reverse PTR record for IPv4 address */ - a = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN, 1); - fail_unless(strcmp(a->qname, buf2) == 0, "url2 not converted correctly! %s\n", a->qname); - fail_unless(short_be(a->qsuffix->qtype) == PICO_DNS_TYPE_PTR, - "qtype2 not properly set!\n"); - fail_unless(short_be(a->qsuffix->qclass) == PICO_DNS_CLASS_IN, - "qclass2 not properly set!\n"); - pico_dns_question_delete((void **)&a); - - /* Reverse PTR record for IPv6 address */ - a = pico_dns_question_create(qurl3, &len, PICO_PROTO_IPV6, - PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN, 1); - fail_unless(strcmp(a->qname, buf3) == 0, "url3 not converted correctly!\n"); - fail_unless(short_be(a->qsuffix->qtype) == PICO_DNS_TYPE_PTR, - "qtype3 not properly set!\n"); - fail_unless(short_be(a->qsuffix->qclass) == PICO_DNS_CLASS_IN, - "qclass3 not properly set!\n"); - pico_dns_question_delete((void **)&a); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_query_create) /* MARK: dns_query_create */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - const char *qurl = "picotcp.com"; - const char *qurl2 = "google.com"; - uint8_t buf[42] = { - 0x00u, 0x00u, - 0x01u, 0x00u, - 0x00u, 0x02u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x06u, 'g', 'o', 'o', 'g', 'l', 'e', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0xc0u, 0x13u, - 0x00u, 0x01u, - 0x00u, 0x01u - }; - uint16_t len = 0; - int ret = 0; - struct pico_dns_question *a = NULL, *b = NULL; - - printf("*********************** starting %s * \n", __func__); - - - a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a, "dns_question_create failed!\n"); - fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); - b = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b, "dns_question_create failed!\n"); - fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); - - pico_tree_insert(&qtree, a); - pico_tree_insert(&qtree, b); - - packet = pico_dns_query_create(&qtree, NULL, NULL, NULL, &len); - fail_if(packet == NULL, "dns_query_create returned NULL!\n"); - fail_unless(0 == memcmp(buf, (void *)packet, 42), - "dns_query_created failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_record_fill_suffix) /* MARK: dns_record_fill_suffix */ -{ - struct pico_dns_record_suffix *suffix = NULL; - - printf("*********************** starting %s * \n", __func__); - - pico_dns_record_fill_suffix(&suffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN, - 120, 4); - - fail_unless((suffix->rtype == short_be(PICO_DNS_TYPE_A) && - suffix->rclass == short_be(PICO_DNS_CLASS_IN) && - suffix->rttl == long_be(120) && - suffix->rdlength == short_be(4)), - "Filling rsuffix failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_record_copy_flat) /* MARK: dns_record_copy_flat */ -{ - struct pico_dns_record *record = NULL; - const char *url = "picotcp.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint8_t buf[128] = { - 0 - }; - uint8_t *ptr = NULL; - uint8_t cmp_buf[27] = { - 0x07, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, - 0x00, 0x01, - 0x00, 0x00, 0x00, 0x78, - 0x00, 0x04, - 0x0A, 0x0A, 0x00, 0x01 - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - record = pico_dns_record_create(url, (void *)rdata, 4, - &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!record, "dns_record_create failed!\n"); - - ptr = buf + 20; - - /* Try to copy the record to a flat buffer */ - ret = pico_dns_record_copy_flat(record, &ptr); - - fail_unless(ret == 0, "dns_record_copy_flat returned error!\n"); - fail_unless(memcmp(buf + 20, cmp_buf, 27) == 0, - "dns_record_copy_flat failed!\n"); - - /* FREE memory */ - pico_dns_record_delete((void **)&record); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_record_copy) /* MARK: dns_record_copy */ -{ - struct pico_dns_record *a = NULL, *b = NULL; - const char *url = "picotcp.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint16_t len = 0; - - a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!a, "dns_record_create failed!\n"); - - printf("*********************** starting %s * \n", __func__); - - /* Try to copy the first DNS record */ - b = pico_dns_record_copy(a); - fail_unless(b != NULL, "dns_record_copy returned NULL!\n"); - fail_unless(a != b, "pointers point to same struct!\n"); - fail_unless(strcmp(a->rname, b->rname) == 0, - "dns_record_copy failed copying names!\n"); - fail_unless(a->rsuffix->rtype == b->rsuffix->rtype, - "dns_record_copy failed copying rtype!\n"); - fail_unless(a->rsuffix->rclass == b->rsuffix->rclass, - "dns_record_copy failed copying rclass!\n"); - fail_unless(a->rsuffix->rttl == b->rsuffix->rttl, - "dns_record_copy failed copying rttl!\n"); - fail_unless(a->rsuffix->rdlength == b->rsuffix->rdlength, - "dns_record_copy failed copying rdlenth!\n"); - fail_unless(memcmp(a->rdata, b->rdata, short_be(b->rsuffix->rdlength)) == 0, - "dns_record_copy failed copying rdata!\n"); - - /* FREE memory */ - pico_dns_record_delete((void **)&a); - pico_dns_record_delete((void **)&b); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_record_delete) /* MARK: dns_record_delete */ -{ - struct pico_dns_record *a = NULL; - const char *url = "picotcp.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - - a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!a, "dns_record_create failed!\n"); - - /* Try to delete the created record */ - ret = pico_dns_record_delete((void **)&a); - fail_unless(ret == 0, "pico_dns_record_delete returned NULL!\n"); - fail_unless(a == NULL, "pico_dns_record_delete failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_record_create) /* MARK: dns_record_create */ -{ - struct pico_dns_record *a = NULL; - const char *url = "picotcp.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!a, "dns_record_create returned NULL!\n"); - fail_unless(strcmp(a->rname, "\x7picotcp\x3com"), - "dns_record_create didn't convert url %s properly!\n", - a->rname); - fail_unless(a->rsuffix->rtype == short_be(PICO_DNS_TYPE_A), - "dns_record_create failed setting rtype!\n"); - fail_unless(a->rsuffix->rclass == short_be(PICO_DNS_CLASS_IN), - "dns_record_create failed setting rclass!\n"); - fail_unless(a->rsuffix->rttl == long_be(120), - "dns_record_create failed setting rttl!\n"); - fail_unless(a->rsuffix->rdlength == short_be(4), - "dns_record_create failed setting rdlenth!\n"); - fail_unless(memcmp(a->rdata, rdata, 4) == 0, - "dns_record_create failed setting rdata!\n"); - - /* TODO: Test PTR records */ - - pico_dns_record_delete((void **)&a); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_answer_create) /* MARK: dns_answer_create */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_RTREE_DECLARE(rtree); - struct pico_dns_record *a = NULL, *b = NULL; - const char *url = "picotcp.com"; - const char *url2 = "google.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint16_t len = 0; - uint8_t buf[62] = { - 0x00u, 0x00u, - 0x85u, 0x00u, - 0x00u, 0x00u, - 0x00u, 0x02u, - 0x00u, 0x00u, - 0x00u, 0x00u, - 0x06u, 'g', 'o', 'o', 'g', 'l', 'e', - 0x03u, 'c', 'o', 'm', - 0x00u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00u, 0x78u, - 0x00u, 0x04u, - 0x0Au, 0x0Au, 0x00u, 0x01u, - 0x07u, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0xc0u, 0x13u, - 0x00u, 0x01u, - 0x00u, 0x01u, - 0x00u, 0x00u, 0x00u, 0x78u, - 0x00u, 0x04u, - 0x0Au, 0x0Au, 0x00u, 0x01u - }; - - printf("*********************** starting %s * \n", __func__); - - a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!a, "dns_record_create returned NULL!\n"); - b = pico_dns_record_create(url2, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 120); - fail_if(!a, "dns_record_create returned NULL!\n"); - - pico_tree_insert(&rtree, a); - pico_tree_insert(&rtree, b); - - /* Try to create an answer packet */ - packet = pico_dns_answer_create(&rtree, NULL, NULL, &len); - fail_if (packet == NULL, "dns_answer_create returned NULL!\n"); - fail_unless(0 == memcmp((void *)packet, (void *)buf, len), - "dns_answer_create failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_namelen_comp) /* MARK: dns_namelen_comp */ -{ - char name[] = "\3www\4tass\2be\0"; - char name_comp[] = "\3www\4tass\2be\xc0\x02"; /* two bytes ofset from start of buf */ - unsigned int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* name without compression */ - ret = pico_dns_namelen_comp(name); - fail_unless(ret == 12, "Namelength is wrong!\n"); - - /* name with compression */ - ret = pico_dns_namelen_comp(name_comp); - fail_unless(ret == 13, "Namelength is wrong!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_decompress_name) /* MARK: dns_decompress_name */ -{ - char name[] = "\4mail\xc0\x02"; - char name2[] = "\xc0\x02"; - char buf[] = "00\6google\3com"; - char *ret; - - printf("*********************** starting %s * \n", __func__); - - /* Test normal DNS name compression */ - ret = pico_dns_decompress_name(name, (pico_dns_packet *)buf); - - /* Fail conditions */ - fail_unless(ret != NULL, "Name ptr returned is NULL"); - fail_unless(strcmp(ret, "\4mail\6google\3com") == 0, "Not correctly decompressed: '%s'!\n", ret); - - /* Free memory */ - PICO_FREE(ret); - ret = NULL; - - /* Test when there is only a pointer */ - ret = pico_dns_decompress_name(name2, (pico_dns_packet *)buf); - - /* Fail conditions */ - fail_unless(ret != NULL, "Name ptr returned is NULL"); - fail_unless(strcmp(ret, "\6google\3com") == 0, "Not correctly decompressed: '%s'!\n", ret); - - /* Free memory */ - PICO_FREE(ret); - ret = NULL; - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_url_get_reverse_len) /* MARK: dns_url_get_reverse_len */ -{ - const char *url_ipv4 = "10.10.0.1"; - const char *url_ipv6 = "2001:0db8:0000:0000:0000:0000:0000:0000"; - uint16_t arpalen = 0; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Try to determine the reverse length of the IPv4 URL */ - len = pico_dns_url_get_reverse_len(url_ipv4, &arpalen, PICO_PROTO_IPV4); - fail_unless(len == (9 + 2) && arpalen == 13, - "dns_url_get_reverse_len failed with IPv4 URL!\n"); - - /* Try to determine the reverse length of the IPv6 URL */ - len = pico_dns_url_get_reverse_len(url_ipv6, &arpalen, PICO_PROTO_IPV6); - fail_unless(len == (63 + 2) && arpalen == 9, - "dns_url_get_reverse_len failed with IPv4 URL!\n"); - - len = pico_dns_url_get_reverse_len(NULL, NULL, PICO_PROTO_IPV4); - fail_unless(len == 0, "dns_url_get_reverse_len with NULL-ptrs failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_url_to_reverse_qname) /* MARK: dns_url_to_reverse_qname */ -{ - const char *url_ipv4 = "10.10.0.1"; - const char *url_ipv6 = "2001:0db8:0000:0000:0000:0000:0000:0000"; - char *qname = NULL; - char cmp_buf1[24] = { - 0x01, '1', - 0x01, '0', - 0x02, '1', '0', - 0x02, '1', '0', - 0x07, 'i', 'n', '-', 'a', 'd', 'd', 'r', - 0x04, 'a', 'r', 'p', 'a', - 0x00 - }; - char cmp_buf[74] = { - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', - 0x01u, '8', 0x01u, 'b', 0x01u, 'd', 0x01u, '0', - 0x01u, '1', 0x01u, '0', 0x01u, '0', 0x01u, '2', - 0x03u, 'I', 'P', '6', - 0x04u, 'A', 'R', 'P', 'A', - 0x00u - }; - - printf("*********************** starting %s * \n", __func__); - - /* Try to reverse IPv4 URL */ - qname = pico_dns_url_to_reverse_qname(url_ipv4, PICO_PROTO_IPV4); - fail_unless(qname != NULL, "dns_url_to_reverse_qname returned NULL!\n"); - fail_unless(strcmp(qname, cmp_buf1) == 0, - "dns_url_to_reverse_qname failed with IPv4 %s!\n", qname); - PICO_FREE(qname); - - /* Try to reverse IPv6 URL */ - qname = pico_dns_url_to_reverse_qname(url_ipv6, PICO_PROTO_IPV6); - fail_unless(qname != NULL, "dns_url_to_reverse_qname returned NULL!\n"); - fail_unless(strcmp(qname, cmp_buf) == 0, - "dns_url_to_reverse_qname failed with IPv6!\n"); - PICO_FREE(qname); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_qname_to_url) /* MARK: dns_qname_to_url */ -{ - char qname[24] = { - 0x01, '1', - 0x01, '0', - 0x02, '1', '0', - 0x02, '1', '0', - 0x07, 'i', 'n', '-', 'a', 'd', 'd', 'r', - 0x04, 'a', 'r', 'p', 'a', - 0x00 - }; - char qname2[13] = { - 0x07, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03, 'c', 'o', 'm', - 0x00 - }; - char qname3[14] = { - 0x08, 'p', 'i', 'c', 'o', '.', 't', 'c', 'p', - 0x03, 'c', 'o', 'm', - 0x00 - }; - char *url = NULL; - - printf("*********************** starting %s * \n", __func__); - - /* Try to convert qname to url */ - url = pico_dns_qname_to_url(qname); - fail_unless(url != NULL, "dns_qname_to_url returned NULL!\n"); - fail_unless(strcmp(url, "1.0.10.10.in-addr.arpa") == 0, - "dns_qname_to_url failed %s!\n", url); - PICO_FREE(url); - - /* Try to convert qname2 to url */ - url = pico_dns_qname_to_url(qname2); - fail_unless(url != NULL, "dns_qname_to_url returned NULL!\n"); - fail_unless(strcmp(url, "picotcp.com") == 0, - "dns_qname_to_url failed %s!\n", url); - PICO_FREE(url); - - /* Try to convert qname2 to url */ - url = pico_dns_qname_to_url(qname3); - fail_unless(url != NULL, "dns_qname_to_url returned NULL!\n"); - fail_unless(strcmp(url, "pico.tcp.com") == 0, - "dns_qname_to_url failed %s!\n", url); - PICO_FREE(url); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_url_to_qname) /* MARK: dns_url_to_qname */ -{ - char qname1[24] = { - 0x01, '1', - 0x01, '0', - 0x02, '1', '0', - 0x02, '1', '0', - 0x07, 'i', 'n', '-', 'a', 'd', 'd', 'r', - 0x04, 'a', 'r', 'p', 'a', - 0x00 - }; - char qname2[13] = { - 0x07, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03, 'c', 'o', 'm', - 0x00 - }; - char *qname = NULL; - - printf("*********************** starting %s * \n", __func__); - - /* Try to convert url to qname1 */ - qname = pico_dns_url_to_qname("1.0.10.10.in-addr.arpa"); - fail_unless(qname != NULL, "dns_url_to_qname returned NULL!\n"); - fail_unless(strcmp(qname, qname1) == 0, - "dns_url_to_qname failed %s!\n", qname); - PICO_FREE(qname); - - /* Try to convert url to qname2 */ - qname = pico_dns_url_to_qname("picotcp.com"); - fail_unless(qname != NULL, "dns_url_to_qname returned NULL!\n"); - fail_unless(strcmp(qname, qname2) == 0, - "dns_url_to_qname failed %s!\n", qname); - PICO_FREE(qname); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_name_to_dns_notation) /* MARK: dns_name_to_dns_notation */ -{ - char qname1[13] = { - 0x07, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03, 'c', 'o', 'm', - 0x00 - }; - char url1[13] = { - 0, 'p', 'i', 'c', 'o', 't', 'c', 'p', '.', 'c', 'o', 'm', 0x00 - }; - char url2[13] = { - 'a', 'p', 'i', 'c', 'o', 't', 'c', 'p', '.', 'c', 'o', 'm', 0x00 - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - ret = pico_dns_name_to_dns_notation(url1, (uint16_t)strlen(url1)); - fail_unless(ret == -1, "dns_name_to_dns_notation didn't check correct!\n"); - - ret = pico_dns_name_to_dns_notation(url2, (uint16_t)strlen(url2)); - fail_unless(ret == 0, "dns_name_to_dns_notation returned error!\n"); - fail_unless(strcmp(url2, qname1) == 0, - "dns_name_to_dns_notation failed! %s\n", url2); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_notation_to_name) /* MARK: dns_notation_to_name */ -{ - char qname1[13] = { - 0x07, 'p', 'i', 'c', 'o', 't', 'c', 'p', - 0x03, 'c', 'o', 'm', - 0x00 - }; - char url1[13] = { - '.', 'p', 'i', 'c', 'o', 't', 'c', 'p', '.', 'c', 'o', 'm', 0x00 - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - ret = pico_dns_notation_to_name(qname1, (uint16_t)strlen(qname1)); - fail_unless(ret == 0, "dns_notation_to_name returned error!\n"); - fail_unless(strcmp(url1, qname1) == 0, - "dns_notation_to_name failed! %s\n", qname1); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_mirror_addr) /* MARK: dns_mirror_addr */ -{ - char url[12] = "192.168.0.1"; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - ret = pico_dns_mirror_addr(url); - fail_unless(ret == 0, "dns_mirror_addr returned error!\n"); - fail_unless(strcmp(url, "1.0.168.192") == 0, - "dns_mirror_addr failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_ptr_ip6_nibble_lo) /* MARK: dns_ptr_ip6_nibble_lo */ -{ - uint8_t byte = 0x34; - char nibble_lo = 0; - - printf("*********************** starting %s * \n", __func__); - - nibble_lo = dns_ptr_ip6_nibble_lo(byte); - fail_unless(nibble_lo == '4', "dns_ptr_ip6_nibble_lo failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_dns_ptr_ip6_nibble_hi) /* MARK: dns_ptr_ip6_nibble_hi */ -{ - uint8_t byte = 0x34; - char nibble_hi = 0; - - printf("*********************** starting %s * \n", __func__); - - nibble_hi = dns_ptr_ip6_nibble_hi(byte); - fail_unless(nibble_hi == '3', "dns_ptr_ip6_nibble_hi failed! '%c'\n", - nibble_hi); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_pico_dns_ipv6_set_ptr) /* MARK: dns_ipv6_set_ptr */ -{ - const char *url_ipv6 = "2001:0db8:0000:0000:0000:0000:0000:0000"; - - char cmpbuf[65] = { - '0', '.', '0', '.', '0', '.', '0', '.', - '0', '.', '0', '.', '0', '.', '0', '.', - '0', '.', '0', '.', '0', '.', '0', '.', - '0', '.', '0', '.', '0', '.', '0', '.', - '0', '.', '0', '.', '0', '.', '0', '.', - '0', '.', '0', '.', '0', '.', '0', '.', - '8', '.', 'b', '.', 'd', '.', '0', '.', - '1', '.', '0', '.', '0', '.', '2', '.', 0x00 - }; - char buf[65] = {}; - - printf("*********************** starting %s * \n", __func__); - - pico_dns_ipv6_set_ptr(url_ipv6, buf); - fail_unless(strcmp(buf, cmpbuf) == 0, - "dns_ipv6_set_ptr failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_dns_rdata_cmp = tcase_create("Unit test for dns_rdata_cmp"); - TCase *TCase_dns_question_cmp = tcase_create("Unit test for dns_question_cmp"); - TCase *TCase_dns_qtree_insert = tcase_create("Unit test for dns_qtree_insert"); - TCase *TCase_dns_record_cmp = tcase_create("Unit test for dns_record_cmp"); - TCase *TCase_dns_rtree_insert = tcase_create("Unit test for dns_rtree_insert"); - TCase *TCase_dns_record_cmp_name_type = tcase_create("Unit test for dns_record_cmp_name_type"); - - /* DNS packet section filling */ - TCase *TCase_pico_dns_fill_packet_header = tcase_create("Unit test for 'pico_dns_fill_packet_header'"); - TCase *TCase_pico_dns_fill_packet_rr_sections = tcase_create("Unit test for 'pico_dns_fill_packet_rr_sections'"); - TCase *TCase_pico_dns_fill_packet_rr_section = tcase_create("Unit test for 'pico_dns_fill_packet_rr_section'"); - TCase *TCase_pico_dns_fill_packet_question_section = tcase_create("Unit test for 'pico_dns_fill_packet_question_sections'"); - - /* DNS packet compression */ - TCase *TCase_pico_dns_packet_compress_find_ptr = tcase_create("Unit test for 'pico_dns_packet_compress_find_ptr'"); - TCase *TCase_pico_dns_packet_compress_name = tcase_create("Unit test for 'pico_dns_packet_compress_name'"); - TCase *TCase_pico_dns_packet_compress = tcase_create("Unit test for 'pico_dns_packet_compress'"); - - /* DNS question functions */ - TCase *TCase_pico_dns_question_fill_qsuffix = tcase_create("Unit test for 'pico_dns_question_fill_qsuffix'"); - TCase *TCase_pico_dns_question_delete = tcase_create("Unit test for 'pico_dns_question_delete'"); - TCase *TCase_pico_dns_question_create = tcase_create("Unit test for 'pico_dns_question_create'"); - - /* DNS query packet creation */ - TCase *TCase_pico_dns_query_create = tcase_create("Unit test for 'pico_dns_query_create'"); - - /* DNS resource record functions */ - TCase *TCase_pico_dns_record_fill_suffix = tcase_create("Unit test for 'pico_dns_record_fill_suffix'"); - TCase *TCase_pico_dns_record_copy_flat = tcase_create("Unit test for 'pico_dns_record_copy_flat'"); - TCase *TCase_pico_dns_record_copy = tcase_create("Unit test for 'pico_dns_record_copy'"); - TCase *TCase_pico_dns_record_delete = tcase_create("Unit test for 'pico_dns_record_delete'"); - TCase *TCAse_pico_dns_record_create = tcase_create("Unit test for 'pico_dns_record_create'"); - - /* DNS answer packet creation */ - TCase *TCase_pico_dns_answer_create = tcase_create("Unit test for 'pico_dns_answer_create'"); - - /* Name conversion and compression function */ - TCase *TCase_pico_dns_namelen_comp = tcase_create("Unit test for 'pico_dns_namelen_comp'"); - TCase *TCase_pico_dns_decompress_name = tcase_create("Unit test for 'pico_dns_decompress_name'"); - TCase *TCase_pico_dns_url_get_reverse_len = tcase_create("Unit test for 'pico_dns_url_get_reverse_len'"); - TCase *TCase_pico_dns_url_to_reverse_qname = tcase_create("Unit test for 'pico_dns_url_to_reverse_qname'"); - TCase *TCase_pico_dns_qname_to_url = tcase_create("Unit test for 'pico_dns_qname_to_url'"); - TCase *TCase_pico_dns_url_to_qname = tcase_create("Unit test for 'pico_dns_url_to_qname'"); - TCase *TCase_pico_dns_name_to_dns_notation = tcase_create("Unit test for 'pico_dns_name_to_dns_notation'"); - TCase *TCase_pico_dns_notation_to_name = tcase_create("Unit test for 'pico_dns_notation_to_name'"); - TCase *TCase_pico_dns_mirror_addr = tcase_create("Unit test for 'pico_dns_mirror_addr'"); - TCase *TCase_dns_ptr_ip6_nibble_lo = tcase_create("Unit test for 'dns_ptr_ip6_nibble_lo'"); - TCase *TCase_dns_ptr_ip6_nibble_hi = tcase_create("Unit test for 'dns_ptr_ip6_nibble_hi'"); - TCase *TCase_pico_dns_ipv6_set_ptr = tcase_create("Unit test for 'pico_dns_ipv6_set_ptr'"); - - tcase_add_test(TCase_dns_rdata_cmp, tc_dns_rdata_cmp); - tcase_add_test(TCase_dns_question_cmp, tc_dns_question_cmp); - tcase_add_test(TCase_dns_qtree_insert, tc_dns_qtree_insert); - tcase_add_test(TCase_dns_record_cmp, tc_dns_record_cmp); - tcase_add_test(TCase_dns_rtree_insert, tc_dns_rtree_insert); - tcase_add_test(TCase_dns_record_cmp_name_type, tc_dns_record_cmp_name_type); - tcase_add_test(TCase_pico_dns_fill_packet_header, tc_pico_dns_fill_packet_header); - tcase_add_test(TCase_pico_dns_fill_packet_rr_section, tc_pico_dns_fill_packet_rr_section); - tcase_add_test(TCase_pico_dns_fill_packet_rr_sections, tc_pico_dns_fill_packet_rr_sections); - tcase_add_test(TCase_pico_dns_fill_packet_question_section, tc_pico_dns_fill_packet_question_section); - tcase_add_test(TCase_pico_dns_packet_compress_find_ptr, tc_pico_dns_packet_compress_find_ptr); - tcase_add_test(TCase_pico_dns_packet_compress_name, tc_pico_dns_packet_compress_name); - tcase_add_test(TCase_pico_dns_packet_compress, tc_pico_dns_packet_compress); - tcase_add_test(TCase_pico_dns_question_fill_qsuffix, tc_pico_dns_question_fill_qsuffix); - tcase_add_test(TCase_pico_dns_question_delete, tc_pico_dns_question_delete); - tcase_add_test(TCase_pico_dns_question_create, tc_pico_dns_question_create); - tcase_add_test(TCase_pico_dns_query_create, tc_pico_dns_query_create); - tcase_add_test(TCase_pico_dns_record_fill_suffix, tc_pico_dns_record_fill_suffix); - tcase_add_test(TCase_pico_dns_record_copy_flat, tc_pico_dns_record_copy_flat); - tcase_add_test(TCase_pico_dns_record_copy, tc_pico_dns_record_copy); - tcase_add_test(TCase_pico_dns_record_delete, tc_pico_dns_record_delete); - tcase_add_test(TCAse_pico_dns_record_create, tc_pico_dns_record_create); - tcase_add_test(TCase_pico_dns_answer_create, tc_pico_dns_answer_create); - tcase_add_test(TCase_pico_dns_namelen_comp, tc_pico_dns_namelen_comp); - tcase_add_test(TCase_pico_dns_decompress_name, tc_pico_dns_decompress_name); - tcase_add_test(TCase_pico_dns_url_get_reverse_len, tc_pico_dns_url_get_reverse_len); - tcase_add_test(TCase_pico_dns_url_to_reverse_qname, tc_pico_dns_url_to_reverse_qname); - tcase_add_test(TCase_pico_dns_qname_to_url, tc_pico_dns_qname_to_url); - tcase_add_test(TCase_pico_dns_url_to_qname, tc_pico_dns_url_to_qname); - tcase_add_test(TCase_pico_dns_name_to_dns_notation, tc_pico_dns_name_to_dns_notation); - tcase_add_test(TCase_pico_dns_notation_to_name, tc_pico_dns_notation_to_name); - tcase_add_test(TCase_pico_dns_mirror_addr, tc_pico_dns_mirror_addr); - tcase_add_test(TCase_dns_ptr_ip6_nibble_lo, tc_dns_ptr_ip6_nibble_lo); - tcase_add_test(TCase_dns_ptr_ip6_nibble_hi, tc_dns_ptr_ip6_nibble_hi); - tcase_add_test(TCase_pico_dns_ipv6_set_ptr, tc_pico_dns_ipv6_set_ptr); - - suite_add_tcase(s, TCase_dns_rdata_cmp); - suite_add_tcase(s, TCase_dns_question_cmp); - suite_add_tcase(s, TCase_dns_qtree_insert); - suite_add_tcase(s, TCase_dns_record_cmp); - suite_add_tcase(s, TCase_dns_rtree_insert); - suite_add_tcase(s, TCase_dns_record_cmp_name_type); - suite_add_tcase(s, TCase_pico_dns_fill_packet_header); - suite_add_tcase(s, TCase_pico_dns_fill_packet_rr_section); - suite_add_tcase(s, TCase_pico_dns_fill_packet_rr_sections); - suite_add_tcase(s, TCase_pico_dns_fill_packet_question_section); - suite_add_tcase(s, TCase_pico_dns_packet_compress_find_ptr); - suite_add_tcase(s, TCase_pico_dns_packet_compress_name); - suite_add_tcase(s, TCase_pico_dns_packet_compress); - suite_add_tcase(s, TCase_pico_dns_question_fill_qsuffix); - suite_add_tcase(s, TCase_pico_dns_question_delete); - suite_add_tcase(s, TCase_pico_dns_question_create); - suite_add_tcase(s, TCase_pico_dns_query_create); - suite_add_tcase(s, TCase_pico_dns_record_fill_suffix); - suite_add_tcase(s, TCase_pico_dns_record_copy); - suite_add_tcase(s, TCase_pico_dns_record_delete); - suite_add_tcase(s, TCAse_pico_dns_record_create); - suite_add_tcase(s, TCase_pico_dns_answer_create); - suite_add_tcase(s, TCase_pico_dns_namelen_comp); - suite_add_tcase(s, TCase_pico_dns_decompress_name); - suite_add_tcase(s, TCase_pico_dns_url_get_reverse_len); - suite_add_tcase(s, TCase_pico_dns_url_to_reverse_qname); - suite_add_tcase(s, TCase_pico_dns_qname_to_url); - suite_add_tcase(s, TCase_pico_dns_url_to_qname); - suite_add_tcase(s, TCase_pico_dns_name_to_dns_notation); - suite_add_tcase(s, TCase_pico_dns_notation_to_name); - suite_add_tcase(s, TCase_pico_dns_mirror_addr); - suite_add_tcase(s, TCase_dns_ptr_ip6_nibble_lo); - suite_add_tcase(s, TCase_dns_ptr_ip6_nibble_hi); - suite_add_tcase(s, TCase_pico_dns_ipv6_set_ptr); - - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} - diff --git a/ext/picotcp/test/unit/modunit_pico_dns_sd.c b/ext/picotcp/test/unit/modunit_pico_dns_sd.c deleted file mode 100644 index 75a6f13..0000000 --- a/ext/picotcp/test/unit/modunit_pico_dns_sd.c +++ /dev/null @@ -1,403 +0,0 @@ -#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_common.h" -#include "pico_tree.h" -#include "pico_dev_mock.c" -#include "modules/pico_dns_sd.c" -#include "check.h" - -Suite *pico_suite(void); -void callback( pico_mdns_rtree *tree, char *str, void *arg); -int dns_sd_init(void); -char text[] = "textvers"; -char text2[] = "pass"; -char text3[] = "color"; -char value[] = "1"; -char value3[] = ""; -void callback( pico_mdns_rtree *tree, - char *str, - void *arg ) -{ - kv_vector vector = { - 0 - }; - - /* This doesn't even gets called, tests exit before possible callback */ - IGNORE_PARAMETER(str); - IGNORE_PARAMETER(arg); - IGNORE_PARAMETER(tree); - fail_unless(pico_dns_sd_register_service("Hello World!", - "_kerberos._udp", - 88, &vector, 120, - callback, NULL) == 0, - "dns_sd_register_service failed!\n"); -} - -int dns_sd_init() -{ - struct mock_device *mock = NULL; - - struct pico_ip4 local = { - .addr = long_be(0x0a280064) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - - mock = pico_mock_create(NULL); - if (!mock) - return -1; - - pico_ipv4_link_add(mock->dev, local, netmask); - - /* Try to initialise the mDNS module right */ - return pico_dns_sd_init("host.local", local, callback, NULL); -} - -START_TEST(tc_dns_sd_kv_vector_strlen) -{ - kv_vector pairs = { - 0 - }; - - pico_dns_sd_kv_vector_add(&pairs, text, value); - pico_dns_sd_kv_vector_add(&pairs, text2, NULL); - pico_dns_sd_kv_vector_add(&pairs, text3, value3); - - fail_unless(pico_dns_sd_kv_vector_strlen(&pairs) == 23, - "dns_sd_kv_vector_strlen returned wrong length!\n"); - - pico_dns_sd_kv_vector_erase(&pairs); -} -END_TEST -START_TEST(tc_dns_sd_srv_record_create) -{ - struct pico_mdns_record *record = NULL; - - uint8_t buf[19] = { - 0, 0, 0, 0, 0, 80, - 5, 'h', 'i', 't', 'e', 'x', - 5, 'l', 'o', 'c', 'a', 'l', - 0 - }; - - record = pico_dns_sd_srv_record_create("test.local", 0, 0, 80, - "hitex.local", 10, - PICO_MDNS_RECORD_UNIQUE); - - fail_unless(strcmp(record->record->rname, "\4test\5local") == 0, - "Name of SRV record not correct!\n"); - fail_unless(short_be(record->record->rsuffix->rtype) == 33, - "Type of SRV record not correctly set!\n"); - fail_unless(short_be(record->record->rsuffix->rclass) == 0x8001, - "Class of SRV record not correctly set!\n"); - fail_unless(short_be(record->record->rsuffix->rdlength) == 19, - "rdlength of SRV record not correctly set!\n"); - fail_unless(long_be(record->record->rsuffix->rttl) == 10, - "TTL of SRV record not correctly set!\n"); - fail_unless(memcmp(record->record->rdata, buf, 19) == 0, - "Rdata of TXT record not correctly set!\n"); - pico_mdns_record_delete((void **)&record); -} -END_TEST -START_TEST(tc_dns_sd_txt_record_create) -{ - struct pico_mdns_record *record = NULL; - kv_vector pairs = { - 0 - }; - - uint8_t buf[23] = { - 10, 't', 'e', 'x', 't', 'v', 'e', 'r', 's', '=', '1', - 4, 'p', 'a', 's', 's', - 6, 'c', 'o', 'l', 'o', 'r', '=' - }; - - pico_dns_sd_kv_vector_add(&pairs, text, value); - pico_dns_sd_kv_vector_add(&pairs, text2, NULL); - pico_dns_sd_kv_vector_add(&pairs, text3, value3); - - record = pico_dns_sd_txt_record_create("test.local", pairs, 10, - PICO_MDNS_RECORD_UNIQUE); - - fail_unless(strcmp(record->record->rname, "\4test\5local") == 0, - "Name of TXT record not correct!\n"); - fail_unless(short_be(record->record->rsuffix->rtype) == 16, - "Type of TXT record not correctly set!\n"); - fail_unless(short_be(record->record->rsuffix->rclass) == 0x8001, - "Class of TXT record not correctly set!\n"); - fail_unless(short_be(record->record->rsuffix->rdlength) == 23, - "rdlength of TXT record not correctly set!\n"); - fail_unless(long_be(record->record->rsuffix->rttl) == 10, - "TTL of TXT record not correctly set!\n"); - fail_unless(memcmp(record->record->rdata, buf, 23) == 0, - "Rdata of TXT record not correctly set!\n"); - pico_mdns_record_delete((void **)&record); -} -END_TEST -START_TEST(tc_dns_sd_kv_create) -{ - key_value_pair_t *pair = NULL; - - pair = pico_dns_sd_kv_create("textvers", "1"); - fail_unless(strcmp(pair->key, "textvers") == 0, - "dns_sd_kv_create failed!\n"); - fail_unless(strcmp(pair->value, "1") == 0, - "dns_sd_kv_create failed!\n"); - PICO_FREE(pair->key); - PICO_FREE(pair->value); - PICO_FREE(pair); - - pair = pico_dns_sd_kv_create("textvers", NULL); - fail_unless(strcmp(pair->key, "textvers") == 0, - "dns_sd_kv_create failed!\n"); - fail_unless(pair->value == NULL, - "dns_sd_kv_create failed!\n"); - PICO_FREE(pair->key); - PICO_FREE(pair); - - pair = pico_dns_sd_kv_create("textvers", ""); - fail_unless(strcmp(pair->key, "textvers") == 0, - "dns_sd_kv_create failed!\n"); - fail_unless(strcmp(pair->value, "") == 0, - "dns_sd_kv_create failed!\n"); - PICO_FREE(pair->key); - PICO_FREE(pair->value); - PICO_FREE(pair); -} -END_TEST -START_TEST(tc_dns_sd_kv_delete) -{ - key_value_pair_t *pair = NULL; - - pair = pico_dns_sd_kv_create("textvers", "1"); - fail_unless(strcmp(pair->key, "textvers") == 0, - "dns_sd_kv_create failed!\n"); - fail_unless(strcmp(pair->value, "1") == 0, - "dns_sd_kv_create failed!\n"); - pico_dns_sd_kv_delete(&pair); - fail_unless(pair == NULL, - "dns_sd_kv_delete failed!\n"); - - pair = pico_dns_sd_kv_create("textvers", NULL); - fail_unless(strcmp(pair->key, "textvers") == 0, - "dns_sd_kv_create failed!\n"); - fail_unless(pair->value == NULL, - "dns_sd_kv_create failed!\n"); - pico_dns_sd_kv_delete(&pair); - fail_unless(pair == NULL, - "dns_sd_kv_delete failed!\n"); - - pair = pico_dns_sd_kv_create("textvers", ""); - fail_unless(strcmp(pair->key, "textvers") == 0, - "dns_sd_kv_create failed!\n"); - fail_unless(strcmp(pair->value, "") == 0, - "dns_sd_kv_create failed!\n"); - pico_dns_sd_kv_delete(&pair); - fail_unless(pair == NULL, - "dns_sd_kv_delete failed!\n"); -} -END_TEST -START_TEST(tc_dns_sd_check_type_format) -{ - fail_unless(pico_dns_sd_check_type_format("_http._tcp") == 0, - "dns_sd_check_type_format failed with correct format!\n"); - fail_unless(pico_dns_sd_check_type_format("_printer._sub._http._tcp") - == 0, - "dns_sd_check_type_format failed with subtype!\n"); - - /* Test too long subtype */ - fail_unless(pico_dns_sd_check_type_format( - "1234567891123456789212345678931234567894123456789512345678961234._sub._http._tcp"), "dns_sd_check_type_format failed with too big subtype!\n"); - - /* Test too long service type with subtype */ - fail_unless(pico_dns_sd_check_type_format( - "printer._sub.0123456789112345678._tcp"), - "dns_sd_check_type_format failed with too big sn w/ sub!\n"); - - /* Test too long service type with subtype */ - fail_unless(pico_dns_sd_check_type_format("0123456789112345678._tcp"), - "dns_sd_check_type_format failed with too big sn!\n"); - -} -END_TEST -START_TEST(tc_dns_sd_check_instance_name_format) -{ - /* Test too long name */ - fail_unless(pico_dns_sd_check_instance_name_format( - "1234567891123456789212345678931234567894123456789512345678961234"), - "dns_sd_check_instance_name_format failed with too big name!\n"); - - fail_unless(pico_dns_sd_check_instance_name_format("Hello World!") == 0, - "dns_sd_check_instance_name_format failed!\n"); -} -END_TEST -START_TEST(tc_dns_sd_create_service_url) -{ - char *service_url = NULL; - - service_url = pico_dns_sd_create_service_url("Hello World!", "_http._tcp"); - - fail_unless(strcmp(service_url, "Hello World!._http._tcp.local") == 0, - "dns_sd_create_service_url failed!\n"); -} -END_TEST -START_TEST(tc_dns_sd_init) -{ - pico_stack_init(); - fail_unless(dns_sd_init() == 0, - "dns_sd_init failed!\n"); -} -END_TEST -START_TEST(tc_dns_sd_register_service) -{ - pico_stack_init(); - dns_sd_init(); -} -END_TEST -START_TEST(tc_dns_sd_browse_service) -{ - /* Not implemented in code */ -} -END_TEST - -START_TEST(tc_dns_sd_kv_vector_add) -{ - kv_vector pairs = { - 0 - }; - char *key = NULL; - - pico_dns_sd_kv_vector_add(&pairs, text, value); - pico_dns_sd_kv_vector_add(&pairs, text2, NULL); - pico_dns_sd_kv_vector_add(&pairs, text3, value3); - - key = pico_dns_sd_kv_vector_get(&pairs, 2)->key; - fail_unless(strcmp("color", key) == 0, - "dns_sd_kv_vector_add failed!\n"); -} -END_TEST -START_TEST(tc_dns_sd_kv_vector_get) -{ - kv_vector pairs = { - 0 - }; - char *key = NULL; - - pico_dns_sd_kv_vector_add(&pairs, text, value); - pico_dns_sd_kv_vector_add(&pairs, text2, NULL); - pico_dns_sd_kv_vector_add(&pairs, text3, value3); - - key = pico_dns_sd_kv_vector_get(&pairs, 2)->key; - fail_unless(strcmp("color", key) == 0, - "dns_sd_kv_vector_get failed!\n"); - - fail_unless(pico_dns_sd_kv_vector_get(&pairs, 3) == NULL, - "dns_sd_kv_vector_get failed @ OOB!\n"); -} -END_TEST -START_TEST(tc_dns_sd_kv_vector_erase) -{ - kv_vector pairs = { - 0 - }; - - pico_dns_sd_kv_vector_add(&pairs, text, value); - pico_dns_sd_kv_vector_add(&pairs, text2, NULL); - pico_dns_sd_kv_vector_add(&pairs, text3, value3); - - pico_dns_sd_kv_vector_erase(&pairs); - - fail_unless(pairs.pairs == NULL, - "dns_sd_kv_vector_erase failed!\n"); - fail_unless(pairs.count == 0, - "dns_sd_kv_vector_erase failed!\n"); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - /* Key-Value pair vector plain creation function */ - TCase *TCase_dns_sd_kv_vector_strlen = tcase_create("Unit test for dns_sd_kv_vector_strlen"); - - /* DNS utility functions */ - TCase *TCase_dns_sd_srv_record_create = tcase_create("Unit test for dns_sd_srv_record_create"); - TCase *TCase_dns_sd_txt_record_create = tcase_create("Unit test for dns_sd_txt_record_create"); - - /* Key-Value pair creation */ - TCase *TCase_dns_sd_kv_create = tcase_create("Unit test for dns_sd_kv_create"); - TCase *TCase_dns_sd_kv_delete = tcase_create("Unit test for dns_sd_kv_delete"); - - /* Utility functions */ - TCase *TCase_dns_sd_check_type_format = tcase_create("Unit test for dns_sd_check_type_format"); - TCase *TCase_dns_sd_check_instance_name_format = tcase_create("Unit test for dns_sd_check_instance_name_format"); - TCase *TCase_dns_sd_create_service_url = tcase_create("Unit test for dns_sd_create_service_url"); - /* DNS SD API functions */ - TCase *TCase_dns_sd_init = tcase_create("Unit test for dns_sd_init"); - TCase *TCase_dns_sd_register_service = tcase_create("Unit test for dns_sd_register_service"); - TCase *TCase_dns_sd_browse_service = tcase_create("Unit test for dns_sd_browse_service"); - - /* Key-Value vector functions */ - TCase *TCase_dns_sd_kv_vector_add = tcase_create("Unit test for dns_sd_kv_vector_add"); - TCase *TCase_dns_sd_kv_vector_get = tcase_create("Unit test for dns_sd_kv_vector_get"); - TCase *TCase_dns_sd_kv_vector_erase = tcase_create("Unit test for dns_sd_kv_vector_erase"); - - /* Key-Value pair vector plain creation function */ - tcase_add_test(TCase_dns_sd_kv_vector_strlen, tc_dns_sd_kv_vector_strlen); - suite_add_tcase(s, TCase_dns_sd_kv_vector_strlen); - - /* DNS utility functions */ - tcase_add_test(TCase_dns_sd_srv_record_create, tc_dns_sd_srv_record_create); - suite_add_tcase(s, TCase_dns_sd_srv_record_create); - tcase_add_test(TCase_dns_sd_txt_record_create, tc_dns_sd_txt_record_create); - suite_add_tcase(s, TCase_dns_sd_txt_record_create); - - /* Key-Value pair creation */ - tcase_add_test(TCase_dns_sd_kv_create, tc_dns_sd_kv_create); - suite_add_tcase(s, TCase_dns_sd_kv_create); - tcase_add_test(TCase_dns_sd_kv_delete, tc_dns_sd_kv_delete); - suite_add_tcase(s, TCase_dns_sd_kv_delete); - - /* Utility functions */ - tcase_add_test(TCase_dns_sd_check_type_format, tc_dns_sd_check_type_format); - suite_add_tcase(s, TCase_dns_sd_check_type_format); - tcase_add_test(TCase_dns_sd_check_instance_name_format, tc_dns_sd_check_instance_name_format); - suite_add_tcase(s, TCase_dns_sd_check_instance_name_format); - tcase_add_test(TCase_dns_sd_create_service_url, tc_dns_sd_create_service_url); - suite_add_tcase(s, TCase_dns_sd_create_service_url); - - /* DNS SD API functions */ - tcase_add_test(TCase_dns_sd_init, tc_dns_sd_init); - suite_add_tcase(s, TCase_dns_sd_init); - tcase_add_test(TCase_dns_sd_register_service, tc_dns_sd_register_service); - suite_add_tcase(s, TCase_dns_sd_register_service); - tcase_add_test(TCase_dns_sd_browse_service, tc_dns_sd_browse_service); - suite_add_tcase(s, TCase_dns_sd_browse_service); - - /* Key-Value vector functions */ - tcase_add_test(TCase_dns_sd_kv_vector_add, tc_dns_sd_kv_vector_add); - suite_add_tcase(s, TCase_dns_sd_kv_vector_add); - tcase_add_test(TCase_dns_sd_kv_vector_get, tc_dns_sd_kv_vector_get); - suite_add_tcase(s, TCase_dns_sd_kv_vector_get); - tcase_add_test(TCase_dns_sd_kv_vector_erase, tc_dns_sd_kv_vector_erase); - suite_add_tcase(s, TCase_dns_sd_kv_vector_erase); - - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_ethernet.c b/ext/picotcp/test/unit/modunit_pico_ethernet.c deleted file mode 100644 index 6f67fa9..0000000 --- a/ext/picotcp/test/unit/modunit_pico_ethernet.c +++ /dev/null @@ -1,315 +0,0 @@ -//#include "pico_config.h" -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_icmp4.h" -#include "pico_icmp6.h" -#include "pico_arp.h" -#include "pico_ethernet.h" -#include "modules/pico_ethernet.c" -#include "check.h" - -#define STARTING() \ - printf("*********************** STARTING %s ***\n", __func__); \ - fflush(stdout) -#define TRYING(s, ...) \ - printf("Trying %s: " s, __func__, ##__VA_ARGS__); \ - fflush(stdout) -#define CHECKING(i) \ - printf("Checking the results of test %2d in %s...", (i)++, \ - __func__); \ - fflush(stdout) -#define SUCCESS() \ - printf(" SUCCES\n"); \ - fflush(stdout) -#define BREAKING(s, ...) \ - printf("Breaking %s: " s, __func__, ##__VA_ARGS__); \ - fflush(stdout) -#define ENDING(i) \ - printf("*********************** ENDING %s *** N TESTS: %d\n", \ - __func__, ((i)-1)); \ - fflush(stdout) -#define DBG(s, ...) \ - printf(s, ##__VA_ARGS__); \ - fflush(stdout) - -Suite *pico_suite(void); - -START_TEST(tc_destination_is_bcast) -{ - /* test this: static int destination_is_bcast(struct pico_frame *f) */ - struct pico_ip6 addr = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - struct pico_ipv6_hdr *h = (struct pico_ipv6_hdr *)f->buffer; - struct pico_ipv4_hdr *h4 = NULL; - - /* Test parameters */ - int ret = 0, count = 0; - - f->net_hdr = (uint8_t*) h; - f->buffer[0] = 0x60; /* Ipv6 */ - - STARTING(); - - TRYING("With wrong protocol -> IPv6\n"); - memcpy(h->dst.addr, addr.addr, PICO_SIZE_IP6); - ret = destination_is_bcast(f); - CHECKING(count); - fail_unless(0 == ret, "Should've returned 0 since IPv6 frame\n"); - SUCCESS(); - pico_frame_discard(f); - - f = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - h4 = (struct pico_ipv4_hdr *)f->buffer; - f->net_hdr = (uint8_t *)h4; - f->buffer[0] = 0x40; /* IPv4 */ - TRYING("With right protocol -> IPv4\n"); - ret = destination_is_bcast(f); - CHECKING(count); - fail_unless(0 == ret, "Should've returned 0 since not a mcast address\n"); - SUCCESS(); - - BREAKING(); - ret = destination_is_bcast(NULL); - CHECKING(count); - fail_unless(0 == ret, "Should've returned 0 since NULL-pointer\n"); - SUCCESS(); - - ENDING(count); -} -END_TEST -START_TEST(tc_destination_is_mcast) -{ - struct pico_ip6 addr = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - struct pico_ip6 mcast = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - struct pico_ip4 addr4 = {0}; - struct pico_ip4 mcast4 = {0}; - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - struct pico_ipv6_hdr *h = (struct pico_ipv6_hdr *)f->buffer; - struct pico_ipv4_hdr *h4 = (struct pico_ipv4_hdr *)f->buffer; - /* Test parameters */ - int ret = 0, count = 0; - - f->net_hdr = (uint8_t*) h; - f->buffer[0] = 0x60; /* Ipv6 */ - - STARTING(); - - pico_string_to_ipv4("232.1.1.0", &(mcast4.addr)); /* 0 */ - pico_string_to_ipv4("10.20.0.1", &(addr4.addr)); - - pico_string_to_ipv6("ff00:0:0:0:0:0:e801:100", (mcast.addr)); /* 0 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:100", (addr.addr)); /* 0 */ - - TRYING("With IPv6 unicast addr\n"); - memcpy(h->dst.addr, addr.addr, PICO_SIZE_IP6); - ret = destination_is_mcast(f); - CHECKING(count); - fail_unless(0 == ret, "Should've returned 0 since not an IPv6 multicast\n"); - SUCCESS(); - - TRYING("With IPv6 multicast addr\n"); - memcpy(h->dst.addr, mcast.addr, PICO_SIZE_IP6); - ret = destination_is_mcast(f); - CHECKING(count); - fail_unless(1 == ret, "Should've returned 1 since an IPv6 multicast\n"); - SUCCESS(); - - pico_frame_discard(f); - f = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - h4 = (struct pico_ipv4_hdr *)f->buffer; - f->net_hdr = (uint8_t *)h4; - f->buffer[0] = 0x40; /* IPv4 */ - - TRYING("With IPv4 unicast addr\n"); - h4->dst = addr4; - ret = destination_is_bcast(f); - CHECKING(count); - fail_unless(0 == ret, "Should've returned 0 since not an IPv4 mcast address\n"); - SUCCESS(); - - TRYING("With IPv4 multicast addr\n"); - h4->dst = mcast4; - ret = destination_is_mcast(f); - CHECKING(count); - fail_unless(1 == ret, "Should've returned 1 since an IPv4 multicast\n"); - SUCCESS(); - - BREAKING(); - ret = destination_is_bcast(NULL); - CHECKING(count); - fail_unless(0 == ret, "Should've returned 0 since NULL-pointer\n"); - SUCCESS(); - - ENDING(count); -} -END_TEST -START_TEST(tc_pico_ipv4_ethernet_receive) -{ - /* test this: static int32_t pico_ipv4_ethernet_receive(struct pico_frame *f) */ - struct pico_frame *f = NULL; - struct pico_ipv4_hdr *h4 = NULL; - int ret = 0, count = 0; - - STARTING(); - - f = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - h4 = (struct pico_ipv4_hdr *)f->buffer; - f->net_hdr = (uint8_t *)h4; - f->buffer[0] = 0x40; /* IPv4 */ - - TRYING("With IPv4 frame\n"); - ret = pico_ipv4_ethernet_receive(f); - CHECKING(count); - fail_unless(ret > 0, "Was correct frame should've returned size of frame\n"); - SUCCESS(); - CHECKING(count); - fail_unless(pico_proto_ipv4.q_in->size == f->buffer_len, "Frame not enqueued\n"); - SUCCESS(); - - ENDING(count); -} -END_TEST -START_TEST(tc_pico_ipv6_ethernet_receive) -{ - /* test this: static int32_t pico_ipv6_ethernet_receive(struct pico_frame *f) */ - struct pico_frame *f = NULL; - struct pico_ipv6_hdr *h = NULL; - - int ret = 0, count = 0; - - STARTING(); - f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - h = (struct pico_ipv6_hdr *)f->buffer; - f->net_hdr = (uint8_t*) h; - f->buffer[0] = 0x40; /* Ipv6 */ - - TRYING("With wrong network type\n"); - ret = pico_ipv6_ethernet_receive(f); - CHECKING(count); - fail_unless(ret == -1, "Wrong type should've returned an error\n"); - SUCCESS(); - - f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - h = (struct pico_ipv6_hdr *)f->buffer; - f->net_hdr = (uint8_t*) h; - f->buffer[0] = 0x60; - TRYING("With correct network type\n"); - ret = pico_ipv6_ethernet_receive(f); - CHECKING(count); - fail_unless(ret == (int32_t)f->buffer_len, "Was correct frame, should've returned success\n"); - SUCCESS(); - CHECKING(count); - fail_unless(pico_proto_ipv6.q_in->size == f->buffer_len, "Frame not enqueued\n"); - SUCCESS(); - - ENDING(count); -} -END_TEST -START_TEST(tc_pico_eth_receive) -{ - struct pico_frame *f = NULL; - struct pico_eth_hdr *eth = NULL; - int ret = 0, count = 0; - - STARTING(); - - f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr) + sizeof(struct pico_eth_hdr)); - f->datalink_hdr = f->buffer; - f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); - eth = (struct pico_eth_hdr *)f->datalink_hdr; - ((uint8_t *)(f->net_hdr))[0] = 0x40; /* Ipv4 */ - - /* ETHERNET PROTOCOL : IPV6 */ - eth->proto = PICO_IDETH_IPV6; - - TRYING("With wrong network type\n"); - ret = pico_eth_receive(f); - CHECKING(count); - fail_unless(ret == -1, "Wrong type should've returned an error\n"); - SUCCESS(); - - f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr) + sizeof(struct pico_eth_hdr)); - f->datalink_hdr = f->buffer; - f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); - eth = (struct pico_eth_hdr *)f->datalink_hdr; - ((uint8_t *)(f->net_hdr))[0] = 0x60; /* Ipv6 */ - - /* ETHERNET PROTOCOL : IPV6 */ - eth->proto = PICO_IDETH_IPV6; - TRYING("With correct network type\n"); - ret = pico_eth_receive(f); - CHECKING(count); - fail_unless(ret == (int32_t)f->buffer_len, "Was correct frame, should've returned success\n"); - SUCCESS(); - CHECKING(count); - fail_unless(pico_proto_ipv6.q_in->size == f->buffer_len, "Frame not enqueued\n"); - SUCCESS(); - - pico_frame_discard(f); - - f = pico_frame_alloc(sizeof(struct pico_ipv4_hdr) + sizeof(struct pico_eth_hdr)); - f->datalink_hdr = f->buffer; - f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); - eth = (struct pico_eth_hdr *)f->datalink_hdr; - ((uint8_t *)(f->net_hdr))[0] = 0x40; /* Ipv4 */ - - TRYING("With wrong frame type\n"); - ret = pico_eth_receive(f); - CHECKING(count); - fail_unless(ret == -1, "should've returned -1 wrong ethernet protocol\n"); - SUCCESS(); - - f = pico_frame_alloc(sizeof(struct pico_ipv4_hdr) + sizeof(struct pico_eth_hdr)); - f->datalink_hdr = f->buffer; - f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); - eth = (struct pico_eth_hdr *)f->datalink_hdr; - ((uint8_t *)(f->net_hdr))[0] = 0x40; /* Ipv4 */ - eth->proto = PICO_IDETH_IPV4; - - TRYING("With IPv4 frame\n"); - ret = pico_eth_receive(f); - CHECKING(count); - fail_unless(ret > 0, "Was correct frame should've returned size of frame\n"); - SUCCESS(); - CHECKING(count); - fail_unless(pico_proto_ipv4.q_in->size == f->buffer_len, "Frame not enqueued\n"); - SUCCESS(); - - ENDING(count); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_destination_is_bcast = tcase_create("Unit test for destination_is_bcast"); - TCase *TCase_destination_is_mcast = tcase_create("Unit test for destination_is_mcast"); - TCase *TCase_pico_ipv4_ethernet_receive = tcase_create("Unit test for pico_ipv4_ethernet_receive"); - TCase *TCase_pico_ipv6_ethernet_receive = tcase_create("Unit test for pico_ipv6_ethernet_receive"); - TCase *TCase_pico_eth_receive = tcase_create("Unit test for pico_eth_receive"); - - tcase_add_test(TCase_destination_is_bcast, tc_destination_is_bcast); - suite_add_tcase(s, TCase_destination_is_bcast); - tcase_add_test(TCase_destination_is_mcast, tc_destination_is_mcast); - suite_add_tcase(s, TCase_destination_is_mcast); - tcase_add_test(TCase_pico_ipv4_ethernet_receive, tc_pico_ipv4_ethernet_receive); - suite_add_tcase(s, TCase_pico_ipv4_ethernet_receive); - tcase_add_test(TCase_pico_ipv6_ethernet_receive, tc_pico_ipv6_ethernet_receive); - suite_add_tcase(s, TCase_pico_ipv6_ethernet_receive); - tcase_add_test(TCase_pico_eth_receive, tc_pico_eth_receive); - suite_add_tcase(s, TCase_pico_eth_receive); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_fragments.c b/ext/picotcp/test/unit/modunit_pico_fragments.c deleted file mode 100644 index 2df932b..0000000 --- a/ext/picotcp/test/unit/modunit_pico_fragments.c +++ /dev/null @@ -1,1234 +0,0 @@ -#include "pico_config.h" -#include "pico_ipv6.h" -#include "pico_icmp6.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_tree.h" -#include "pico_constants.h" -#include "pico_fragments.h" -#include "./modules/pico_fragments.c" -#include "check.h" - -Suite *pico_suite(void); -/* Mock! */ -static int transport_recv_called = 0; -static uint32_t buffer_len_transport_receive = 0; -#define TESTPROTO 0x99 -#define TESTID 0x11 -int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto) -{ - fail_if(proto != TESTPROTO); - transport_recv_called++; - buffer_len_transport_receive = f->buffer_len; - pico_frame_discard(f); - return 0; -} - -static int timer_add_called = 0; -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(expire); - IGNORE_PARAMETER(arg); - fail_if(timer != pico_frag_expire); - timer_add_called++; - return 0; -} - -static int timer_cancel_called = 0; -void pico_timer_cancel(uint32_t id) -{ - IGNORE_PARAMETER(id); - timer_cancel_called++; -} - -static int icmp4_frag_expired_called = 0; -int pico_icmp4_frag_expired(struct pico_frame *f) -{ - fail_unless(IS_IPV4(f)); - icmp4_frag_expired_called++; - return 0; -} - -static int icmp6_frag_expired_called = 0; -int pico_icmp6_frag_expired(struct pico_frame *f) -{ - fail_unless(IS_IPV6(f)); - icmp6_frag_expired_called++; - return 0; -} - - -START_TEST(tc_pico_ipv6_frag_compare) -{ - struct pico_frame *a, *b; - a = pico_frame_alloc(10); - fail_if(!a); - b = pico_frame_alloc(10); - fail_if(!b); - a->frag = 0xaa00; - b->frag = 0xbb00; - fail_unless(pico_ipv6_frag_compare(a, b) < 0); - fail_unless(pico_ipv6_frag_compare(b, a) > 0); - b->frag = 0xaa00; - fail_unless(pico_ipv6_frag_compare(a, b) == 0); - pico_frame_discard(a); - pico_frame_discard(b); -} -END_TEST - -START_TEST(tc_pico_ipv4_frag_compare) -{ - struct pico_frame *a, *b; - a = pico_frame_alloc(10); - fail_if(!a); - b = pico_frame_alloc(10); - fail_if(!b); - a->frag = 0xaa00; - b->frag = 0xbb00; - fail_unless(pico_ipv4_frag_compare(a, b) < 0); - fail_unless(pico_ipv4_frag_compare(b, a) > 0); - b->frag = 0xaa00; - fail_unless(pico_ipv4_frag_compare(a, b) == 0); - pico_frame_discard(a); - pico_frame_discard(b); -} -END_TEST - -START_TEST(tc_pico_ipv6_fragments_complete) -{ - struct pico_frame *a, *b; - transport_recv_called = 0; - timer_cancel_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = 1; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20; /* off = 32 */ - - pico_tree_insert(&ipv6_fragments, a); - pico_tree_insert(&ipv6_fragments, b); - - pico_set_mm_failure(1); - pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV6); - fail_if(transport_recv_called != 0); - fail_if(timer_cancel_called != 0); - - pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV6); - fail_if(transport_recv_called != 1); - fail_if(timer_cancel_called != 1); -} -END_TEST - -START_TEST(tc_pico_ipv4_fragments_complete) -{ - struct pico_frame *a, *b; - transport_recv_called = 0; - timer_cancel_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u; /* off = 32 */ - - pico_tree_insert(&ipv4_fragments, a); - pico_tree_insert(&ipv4_fragments, b); - - pico_set_mm_failure(1); - pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV4); - fail_if(transport_recv_called != 0); - fail_if(timer_cancel_called != 0); - - pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV4); - fail_if(transport_recv_called != 1); - fail_if(timer_cancel_called != 1); -} -END_TEST - -START_TEST(tc_pico_fragments_complete) -{ - /* Done in the two tests above */ -} -END_TEST - -START_TEST(tc_pico_fragments_empty_tree) -{ - PICO_TREE_DECLARE(tree, pico_ipv4_frag_compare); - struct pico_frame *a = NULL, *b = NULL; - - pico_fragments_empty_tree(NULL); - - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - /* Make sure we have different frames a and b (because of compare functions in PICO_TREE_DECLARE) */ - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u; /* off = 32 */ - - /* Insert them in the tree */ - pico_tree_insert(&tree, a); - pico_tree_insert(&tree, b); - - pico_fragments_empty_tree(&tree); - - /* Is tree empty? */ - fail_if(!pico_tree_empty(&tree)); -} -END_TEST - -START_TEST(tc_pico_fragments_check_complete) -{ - struct pico_frame *a, *b; - fail_if(pico_fragments_check_complete(&ipv4_fragments, TESTPROTO, PICO_PROTO_IPV4) != 1); - fail_if(pico_fragments_check_complete(&ipv6_fragments, TESTPROTO, PICO_PROTO_IPV6) != 1); - - /* Case 1: IPV4 all packets received */ - transport_recv_called = 0; - timer_cancel_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u; /* off = 32 */ - - pico_tree_insert(&ipv4_fragments, a); - pico_tree_insert(&ipv4_fragments, b); - - fail_if(pico_fragments_check_complete(&ipv4_fragments, TESTPROTO, PICO_PROTO_IPV4) != 0); - fail_if(transport_recv_called != 1); - fail_if(timer_cancel_called != 1); - - /* Case 2: IPV6 all packets received */ - transport_recv_called = 0; - timer_cancel_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = 1; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20; /* off = 32 */ - - pico_tree_insert(&ipv6_fragments, a); - pico_tree_insert(&ipv6_fragments, b); - - fail_if(pico_fragments_check_complete(&ipv6_fragments, TESTPROTO, PICO_PROTO_IPV6) != 0); - fail_if(transport_recv_called != 1); - fail_if(timer_cancel_called != 1); - - - /* Case 3: IPV4 NOT all packets received */ - transport_recv_called = 0; - timer_cancel_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u | PICO_IPV4_MOREFRAG; /* off = 32 + more frags */ - /* b->frag = PICO_IPV4_MOREFRAG; /\* more frags *\/ */ - - pico_tree_insert(&ipv4_fragments, a); - pico_tree_insert(&ipv4_fragments, b); - - fail_if(pico_fragments_check_complete(&ipv4_fragments, TESTPROTO, PICO_PROTO_IPV4) == 0); - fail_if(transport_recv_called != 0); - fail_if(timer_cancel_called != 0); - - /* Case 4: IPV6 NOT all packets received */ - transport_recv_called = 0; - timer_cancel_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = 1; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 1; /* more frags */ - - pico_tree_insert(&ipv6_fragments, a); - pico_tree_insert(&ipv6_fragments, b); - - fail_if(pico_fragments_check_complete(&ipv6_fragments, TESTPROTO, PICO_PROTO_IPV6) == 0); - fail_if(transport_recv_called != 0); - fail_if(timer_cancel_called != 0); -} -END_TEST - -START_TEST(tc_pico_fragments_send_notify) -{ - struct pico_frame *a = NULL; - char ipv4_multicast_address[] = { - "224.0.0.1" - }; - - icmp4_frag_expired_called = 0; - - /* Case 1: NULL fragment */ - - pico_fragments_send_notify(NULL); - - /* Notify should not be send when supplied a NULL argument */ - fail_if(icmp4_frag_expired_called); - - /* Case 2: fragment with offset > 0 */ - a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv4_hdr); - a->buffer[0] = 0x40; /* IPV4 */ - a->frag = 0x20 >> 3u; /* off = 32 */ - - pico_fragments_send_notify(a); - - /* fragment has offset > 0, no notify should be sent */ - fail_if(icmp4_frag_expired_called); - - /* Case 3: fragment with offset > 0 & multicast address */ - pico_string_to_ipv4(ipv4_multicast_address, &((struct pico_ipv4_hdr*)(a->net_hdr))->dst.addr); - pico_fragments_send_notify(a); - - /* fragment has offset > 0 AND multicast address, no notify should be sent */ - fail_if(icmp4_frag_expired_called); - - /* Case 4: fragment with offset == 0 */ - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv4_hdr); - a->buffer[0] = 0x40; /* IPV4 */ - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - pico_string_to_ipv4("127.0.0.1", &((struct pico_ipv4_hdr*)(a->net_hdr))->dst.addr); /* Set a non-nulticast address */ - - pico_fragments_send_notify(a); - - /* fragment has offset == 0, notify should be sent */ - fail_if(!icmp4_frag_expired_called); - - /* Case 5: fragment with offset == 0 & multicast address */ - icmp4_frag_expired_called = 0; /* reset flag */ - pico_string_to_ipv4(ipv4_multicast_address, &((struct pico_ipv4_hdr*)(a->net_hdr))->dst.addr); - - pico_fragments_send_notify(a); - - /* fragment has offset == 0 but multicast address, notify should NOT sent */ - fail_if(icmp4_frag_expired_called); - - /* Cleanup */ - pico_frame_discard(a); -} -END_TEST - - -START_TEST(tc_pico_frag_expire) -{ - struct pico_frame *a, *b; - /* Addr setup, choose a unicast addr */ - struct pico_ip6 addr_1 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - char ipv4_multicast_address[] = { - "224.0.0.1" - }; - struct pico_ip6 ipv6_multicast_addr = {{ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - - /* Clear env vars */ - icmp4_frag_expired_called = 0; - icmp6_frag_expired_called = 0; - - /* Common tests */ - /* Case 1: tree is NULL */ - pico_frag_expire(0, NULL); - fail_if(icmp4_frag_expired_called); - fail_if(icmp6_frag_expired_called); - - /* IPV4 TESTS */ - /* Initial setup */ - a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - /* Case 1: first fragment was not received, do not send notify + empty tree */ - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv4_hdr); - a->buffer[0] = 0x40; /* IPV4 */ - a->frag = 0x20 >> 3u; /* off = 32 */ - - pico_tree_insert(&ipv4_fragments, a); - - pico_frag_expire(0, (void*)(&ipv4_fragments)); - fail_if(icmp4_frag_expired_called); - fail_if(!pico_tree_empty(&ipv4_fragments)); - - /* Case 2: first fragment was received, send notify + empty tree */ - - b->net_hdr = b->buffer; - b->net_len = sizeof(struct pico_ipv4_hdr); - b->buffer[0] = 0x40; /* IPV4 */ - b->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - pico_tree_insert(&ipv4_fragments, b); - - pico_frag_expire(0, (void*)(&ipv4_fragments)); - fail_if(!icmp4_frag_expired_called); - fail_if(!pico_tree_empty(&ipv4_fragments)); - - /* Case 3: first fragment was received but it is multicast, do not send notify + empty tree */ - /* Reallocate frame, it was discarded in the last pico_frag_expire() */ - b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - /* Reset env vars */ - icmp4_frag_expired_called = 0; - - b->net_hdr = b->buffer; - b->net_len = sizeof(struct pico_ipv4_hdr); - b->buffer[0] = 0x40; /* IPV4 */ - b->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - pico_string_to_ipv4(ipv4_multicast_address, &((struct pico_ipv4_hdr*)(b->net_hdr))->dst.addr); - - pico_tree_insert(&ipv4_fragments, b); - - pico_frag_expire(0, (void*)(&ipv4_fragments)); - fail_if(icmp4_frag_expired_called); - fail_if(!pico_tree_empty(&ipv4_fragments)); - - - /* IPV6 TESTS */ - /* re-allocate frames, they were discarded in pico_frag_expire */ - a = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - /* Case 4: first fragment was not received, do not send notify + empty tree */ - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv6_hdr); - a->buffer[0] = 0x60; /* IPV6 */ - a->frag = 0x20; /* off = 32 */ - memcpy(((struct pico_ipv6_hdr*)(a->net_hdr))->dst.addr, addr_1.addr, PICO_SIZE_IP6); - - pico_tree_insert(&ipv6_fragments, a); - - pico_frag_expire(0, (void*)(&ipv6_fragments)); - fail_if(icmp6_frag_expired_called); - fail_if(!pico_tree_empty(&ipv6_fragments)); - - /* Case 5: first fragment was received, send notify + empty tree */ - - b->net_hdr = b->buffer; - b->net_len = sizeof(struct pico_ipv6_hdr); - b->buffer[0] = 0x60; /* IPV6 */ - b->frag = 1; - memcpy(((struct pico_ipv6_hdr*)(b->net_hdr))->dst.addr, addr_1.addr, PICO_SIZE_IP6); - - pico_tree_insert(&ipv6_fragments, b); - - pico_frag_expire(0, (void*)(&ipv6_fragments)); - fail_if(!icmp6_frag_expired_called); - fail_if(!pico_tree_empty(&ipv6_fragments)); - - /* Case 6: first fragment was received but it is multicast, do not send notify + empty tree */ - /* Reallocate frame, it was discarded in the last pico_frag_expire() */ - b = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - /* Reset env vars */ - icmp6_frag_expired_called = 0; - - b->net_hdr = b->buffer; - b->net_len = sizeof(struct pico_ipv4_hdr); - b->buffer[0] = 0x60; /* IPV4 */ - b->frag = 1; - - memcpy(((struct pico_ipv6_hdr*)(b->net_hdr))->dst.addr, ipv6_multicast_addr.addr, PICO_SIZE_IP6); - - pico_tree_insert(&ipv6_fragments, b); - - pico_frag_expire(0, (void*)(&ipv6_fragments)); - fail_if(icmp6_frag_expired_called); - fail_if(!pico_tree_empty(&ipv6_fragments)); - -} -END_TEST -START_TEST(tc_pico_ipv6_frag_timer_on) -{ - /* Reset env variable */ - timer_add_called = 0; - - pico_ipv6_frag_timer_on(); - - /* Was timer added? */ - fail_if(!timer_add_called); -} -END_TEST -START_TEST(tc_pico_ipv4_frag_timer_on) -{ - /* Reset env variable */ - timer_add_called = 0; - - pico_ipv4_frag_timer_on(); - - /* Was timer added? */ - fail_if(!timer_add_called); -} -END_TEST -START_TEST(tc_pico_ipv6_frag_match) -{ - struct pico_frame *a, *b; - struct pico_ipv6_hdr *ha, *hb; - - /* Addr setup */ - struct pico_ip6 addr_1 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - struct pico_ip6 addr_2 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 }}; - - /* Inital setup */ - a = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - /* Case 1: net hdr(s) are NULL */ - a->net_hdr = NULL; - b->net_hdr = NULL; - - fail_if(pico_ipv6_frag_match(a, b) != -2); - - /* Init a frame */ - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv6_hdr); - - fail_if(pico_ipv6_frag_match(a, b) != -2); - - /* Init b frame */ - b->net_hdr = b->buffer; - b->net_len = sizeof(struct pico_ipv6_hdr); - - /* Init hdrs for rest of tests*/ - ha = (struct pico_ipv6_hdr *)a->net_hdr; - hb = (struct pico_ipv6_hdr *)b->net_hdr; - - /* Case 2: src addr are different*/ - /* Init a and b net hdr adresses */ - memcpy(ha->src.addr, addr_1.addr, PICO_SIZE_IP6); - memcpy(ha->dst.addr, addr_2.addr, PICO_SIZE_IP6); - memcpy(hb->src.addr, addr_2.addr, PICO_SIZE_IP6); - memcpy(hb->dst.addr, addr_2.addr, PICO_SIZE_IP6); - - fail_if(pico_ipv6_frag_match(a, b) != 1); - - /* Case 3: dst addr are different*/ - /* Init a and b net hdr adresses */ - memcpy(ha->src.addr, addr_1.addr, PICO_SIZE_IP6); - memcpy(ha->dst.addr, addr_2.addr, PICO_SIZE_IP6); - memcpy(hb->src.addr, addr_1.addr, PICO_SIZE_IP6); - memcpy(hb->dst.addr, addr_1.addr, PICO_SIZE_IP6); - - fail_if(pico_ipv6_frag_match(a, b) != 2); - - /* Case 4: fragments are the same (src and dst are the same)*/ - /* Init a and b net hdr adresses */ - memcpy(ha->src.addr, addr_1.addr, PICO_SIZE_IP6); - memcpy(ha->dst.addr, addr_2.addr, PICO_SIZE_IP6); - memcpy(hb->src.addr, addr_1.addr, PICO_SIZE_IP6); - memcpy(hb->dst.addr, addr_2.addr, PICO_SIZE_IP6); - - fail_if(pico_ipv6_frag_match(a, b) != 0); - - /* Cleanup */ - pico_frame_discard(a); - pico_frame_discard(b); -} -END_TEST -START_TEST(tc_pico_ipv4_frag_match) -{ - struct pico_frame *a, *b; - struct pico_ipv4_hdr *ha, *hb; - - /* Addr setup */ - struct pico_ip4 addr_1 = { - .addr = long_be(0x0a280064) - }; - - struct pico_ip4 addr_2 = { - .addr = long_be(0x0a280312) - }; - - /* Case 1: frames are NULL */ - a = NULL; - b = NULL; - - fail_if(pico_ipv4_frag_match(a, b) != -1); - - /* setup */ - a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - - /* Case 2: net hdr(s) are NULL */ - a->net_hdr = NULL; - b->net_hdr = NULL; - - fail_if(pico_ipv4_frag_match(a, b) != -2); - - /* Init a frame */ - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv4_hdr); - - fail_if(pico_ipv4_frag_match(a, b) != -2); - - /* Init b frame */ - b->net_hdr = b->buffer; - b->net_len = sizeof(struct pico_ipv4_hdr); - - /* Init hdrs for rest of tests*/ - ha = (struct pico_ipv4_hdr *)a->net_hdr; - hb = (struct pico_ipv4_hdr *)b->net_hdr; - - /* Case 3: src addr are different*/ - /* Init a and b net hdr adresses */ - ha->src = addr_1; - ha->dst = addr_2; - hb->src = addr_2; - hb->dst = addr_2; - - fail_if(pico_ipv4_frag_match(a, b) != 1); - - /* Case 4: dst addr are different*/ - /* Init a and b net hdr adresses */ - ha->src = addr_1; - ha->dst = addr_2; - hb->src = addr_1; - hb->dst = addr_1; - - fail_if(pico_ipv4_frag_match(a, b) != 2); - - /* Case 5: fragments are the same (src and dst are the same)*/ - /* Init a and b net hdr adresses */ - ha->src = addr_1; - ha->dst = addr_2; - hb->src = addr_1; - hb->dst = addr_2; - - fail_if(pico_ipv4_frag_match(a, b) != 0); - - /* Cleanup */ - pico_frame_discard(a); - pico_frame_discard(b); -} -END_TEST - -START_TEST(tc_pico_fragments_get_header_length) -{ - fail_unless(pico_fragments_get_header_length(PICO_PROTO_IPV4) == PICO_SIZE_IP4HDR); - - fail_unless(pico_fragments_get_header_length(PICO_PROTO_IPV6) == PICO_SIZE_IP6HDR); - - fail_unless(pico_fragments_get_header_length(1) == 0); -} -END_TEST - -START_TEST(tc_pico_fragments_get_more_flag) -{ - struct pico_frame *a = NULL, *b = NULL; - - a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - - a->net_hdr = a->buffer; - a->net_len = sizeof(struct pico_ipv4_hdr); - a->buffer[0] = 0x40; /* IPV4 */ - a->frag = PICO_IPV4_MOREFRAG; /* Set more flag */ - - b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - b->net_hdr = a->buffer; - b->net_len = sizeof(struct pico_ipv6_hdr); - b->buffer[0] = 0x60; /* IPV6 */ - b->frag = 0x1; /* set more flag */ - - fail_unless(pico_fragments_get_more_flag(NULL, PICO_PROTO_IPV4) == 0); - fail_unless(pico_fragments_get_more_flag(NULL, PICO_PROTO_IPV6) == 0); - - /* More flag set in IPV4 */ - fail_unless(pico_fragments_get_more_flag(a, PICO_PROTO_IPV4) == 1); - - /* More flag set in IPV6 */ - fail_unless(pico_fragments_get_more_flag(b, PICO_PROTO_IPV6) == 1); - - /* More flag NOT set in IPV4 */ - a->frag = 0; - fail_unless(pico_fragments_get_more_flag(a, PICO_PROTO_IPV4) == 0); - - /* More flag NOT set in IPV6 */ - b->frag = 0; - fail_unless(pico_fragments_get_more_flag(b, PICO_PROTO_IPV6) == 0); - - /* Invalid net argument */ - fail_unless(pico_fragments_get_more_flag(a, 1) == 0); - fail_unless(pico_fragments_get_more_flag(b, 1) == 0); - - /* Cleanup */ - pico_frame_discard(a); - pico_frame_discard(b); -} -END_TEST - -START_TEST(tc_pico_fragments_get_offset) -{ - struct pico_frame *a=NULL, *b = NULL; - - b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - /* IPV4 with fragment offset > 0 */ - b->frag = 0x20 >> 3u; /* off = 32 */ - fail_unless(pico_fragments_get_offset(b, PICO_PROTO_IPV4) == 32); - - /* IPV4 with fragment offset == 0 */ - b->frag = 0; /* off = 0 */ - fail_unless(pico_fragments_get_offset(b, PICO_PROTO_IPV4) == 0); - - /* Invalid net argument */ - fail_unless(pico_fragments_get_offset(b, 1) == 0); - - a = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - fail_if(!a); - printf("Allocated frame, %p\n", a); - - /* IPV6 with fragment offset > 0 */ - a->frag = 0x20; /* off = 32 */ - fail_unless(pico_fragments_get_offset(a, PICO_PROTO_IPV6) == 32); - - /* IPV6 with fragment offset == 0 */ - a->frag = 1; /* off = 0 */ - fail_unless(pico_fragments_get_offset(a, PICO_PROTO_IPV6) == 0); - - /* Invalid net argument */ - fail_unless(pico_fragments_get_offset(a, 1) == 0); - - /* Invalid frame argument */ - fail_unless(pico_fragments_get_offset(NULL, PICO_PROTO_IPV4) == 0); - fail_unless(pico_fragments_get_offset(NULL, PICO_PROTO_IPV6) == 0); - fail_unless(pico_fragments_get_offset(NULL, 1) == 0); - - pico_frame_discard(a); - pico_frame_discard(b); -} -END_TEST - -START_TEST(tc_pico_fragments_reassemble) -{ - struct pico_frame *a, *b; - - /* NULL tree */ - transport_recv_called = 0; - buffer_len_transport_receive = 0; - fail_if(pico_fragments_reassemble(NULL, 0, TESTPROTO, PICO_PROTO_IPV4) != -1); - fail_if(transport_recv_called); - - /* Empty tree */ - transport_recv_called = 0; - buffer_len_transport_receive = 0; - fail_if(pico_fragments_reassemble(&ipv4_fragments, 0, TESTPROTO, PICO_PROTO_IPV4) != -2); - fail_if(transport_recv_called); - - /* Empty tree */ - transport_recv_called = 0; - buffer_len_transport_receive = 0; - fail_if(pico_fragments_reassemble(&ipv6_fragments, 0, TESTPROTO, PICO_PROTO_IPV6) != -2); - fail_if(transport_recv_called); - - /* Case 1: IPV4 , everything good */ - transport_recv_called = 0; - buffer_len_transport_receive = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u; /* off = 32 */ - - pico_tree_insert(&ipv4_fragments, a); - pico_tree_insert(&ipv4_fragments, b); - - fail_if(pico_fragments_reassemble(&ipv4_fragments, 64, TESTPROTO, PICO_PROTO_IPV4) != 0); - fail_if(transport_recv_called != 1); - fail_if(buffer_len_transport_receive != 64 + PICO_SIZE_IP4HDR); - fail_if(!pico_tree_empty(&ipv4_fragments)); - - /* Case 2: IPV6 , everything good */ - transport_recv_called = 0; - buffer_len_transport_receive = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = 1; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20; /* off = 32 */ - - pico_tree_insert(&ipv6_fragments, a); - pico_tree_insert(&ipv6_fragments, b); - - fail_if(pico_fragments_reassemble(&ipv6_fragments, 64, TESTPROTO, PICO_PROTO_IPV6) != 0); - fail_if(transport_recv_called != 1); - fail_if(buffer_len_transport_receive != 64 + PICO_SIZE_IP6HDR); - fail_if(!pico_tree_empty(&ipv4_fragments)); - - /* Case 3: IPV4 with mm failure*/ - transport_recv_called = 0; - buffer_len_transport_receive = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u; /* off = 32 */ - - pico_tree_insert(&ipv4_fragments, a); - pico_tree_insert(&ipv4_fragments, b); - - pico_set_mm_failure(1); - fail_if(pico_fragments_reassemble(&ipv4_fragments, 64, TESTPROTO, PICO_PROTO_IPV4) != 1); - fail_if(transport_recv_called == 1); - fail_if(buffer_len_transport_receive != 0); - fail_if(pico_tree_empty(&ipv4_fragments)); - - /* Case 4: IPV6 with mm failure */ - transport_recv_called = 0; - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = 1; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20; /* off = 32 */ - - pico_tree_insert(&ipv6_fragments, a); - pico_tree_insert(&ipv6_fragments, b); - - pico_set_mm_failure(1); - fail_if(pico_fragments_reassemble(&ipv6_fragments, 64, TESTPROTO, PICO_PROTO_IPV6) != 1); - fail_if(transport_recv_called == 1); - fail_if(buffer_len_transport_receive != 0); - fail_if(pico_tree_empty(&ipv6_fragments)); -} -END_TEST - -START_TEST(tc_pico_ipv6_process_frag) -{ - struct pico_ipv6_exthdr *hdr = NULL; - struct pico_frame *a = NULL, *b = NULL, *c = NULL; - - /* NULL args provided */ - ipv6_cur_frag_id = 0; - timer_add_called = 0; - pico_ipv6_process_frag(hdr, a, TESTPROTO); - fail_if(ipv6_cur_frag_id != 0); - fail_if(timer_add_called != 0); - - /* init hdr */ - hdr = PICO_ZALLOC(sizeof(struct pico_ipv6_exthdr)); - hdr->ext.frag.id[0]= 0xF; - - /* NULL frame provided */ - ipv6_cur_frag_id = 0; - timer_add_called = 0; - pico_ipv6_process_frag(hdr, a, TESTPROTO); - fail_if(ipv6_cur_frag_id != 0); - fail_if(timer_add_called != 0); - - /* init frame */ - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - c = pico_frame_alloc(64 + 20); - fail_if(!c); - printf("Allocated frame, %p\n", c); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = 1; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 | 0x1; /* off = 32 */ - - c->net_hdr = c->buffer; - c->net_len = 20; - c->transport_len = 32; - c->transport_hdr = c->buffer + 20; - c->frag = 0x40; /* off = 64 */ - - /* Case 1: Empty fragments tree */ - ipv6_cur_frag_id = 0; - timer_add_called = 0; - /* make sure tree is empty */ - fail_if(!pico_tree_empty(&ipv6_fragments)); - - pico_ipv6_process_frag(hdr, a, TESTPROTO); - fail_if(ipv6_cur_frag_id != IP6_FRAG_ID(hdr)); - fail_if(timer_add_called != 1); - fail_if(pico_tree_empty(&ipv6_fragments)); - /* make sure we added the fragment to the tree */ - fail_if(((struct pico_frame *)pico_tree_first(&ipv6_fragments))->buffer != a->buffer); - - /* Case 2: Adding second fragment */ - timer_add_called = 0; - pico_ipv6_process_frag(hdr, b, TESTPROTO); - fail_if(ipv6_cur_frag_id != IP6_FRAG_ID(hdr)); - fail_if(timer_add_called != 0); - fail_if(pico_tree_empty(&ipv6_fragments)); - /* make sure we added the fragment to the tree */ - fail_if(((struct pico_frame *)pico_tree_last(&ipv6_fragments))->buffer != b->buffer); - - /* Case 3: Adding final fragment */ - timer_cancel_called = 0; - transport_recv_called = 0; - buffer_len_transport_receive = 0; - pico_ipv6_process_frag(hdr, c, TESTPROTO); - fail_if(ipv6_cur_frag_id != IP6_FRAG_ID(hdr)); - fail_if(timer_cancel_called != 1); - fail_if(transport_recv_called != 1); - fail_if(buffer_len_transport_receive != 96 + PICO_SIZE_IP6HDR); - /* Everything was received, tree should be empty */ - fail_if(!pico_tree_empty(&ipv6_fragments)); - - /* Cleanup */ - pico_fragments_empty_tree(&ipv6_fragments); - pico_frame_discard(a); - pico_frame_discard(b); - pico_frame_discard(c); -} -END_TEST - -START_TEST(tc_pico_ipv4_process_frag) -{ - struct pico_ipv4_hdr *hdr = NULL; - struct pico_frame *a = NULL, *b = NULL, *c = NULL; - - /* NULL args provided */ - ipv4_cur_frag_id = 0; - timer_add_called = 0; - pico_ipv4_process_frag(hdr, a, TESTPROTO); - fail_if(ipv4_cur_frag_id != 0); - fail_if(timer_add_called != 0); - - /* init hdr */ - hdr = PICO_ZALLOC(sizeof(struct pico_ipv4_hdr)); - hdr->id = TESTID; - - /* NULL frame provided */ - ipv4_cur_frag_id = 0; - timer_add_called = 0; - pico_ipv4_process_frag(hdr, a, TESTPROTO); - fail_if(ipv4_cur_frag_id != 0); - fail_if(timer_add_called != 0); - - /* init frame */ - a = pico_frame_alloc(32 + 20); - fail_if(!a); - printf("Allocated frame, %p\n", a); - b = pico_frame_alloc(32 + 20); - fail_if(!b); - printf("Allocated frame, %p\n", b); - c = pico_frame_alloc(64 + 20); - fail_if(!c); - printf("Allocated frame, %p\n", c); - - a->net_hdr = a->buffer; - a->net_len = 20; - a->transport_len = 32; - a->transport_hdr = a->buffer + 20; - a->frag = PICO_IPV4_MOREFRAG; /* more frags */ - - b->net_hdr = b->buffer; - b->net_len = 20; - b->transport_len = 32; - b->transport_hdr = b->buffer + 20; - b->frag = 0x20 >> 3u | PICO_IPV4_MOREFRAG; /* off = 32 + more frags*/ - - c->net_hdr = c->buffer; - c->net_len = 20; - c->transport_len = 32; - c->transport_hdr = c->buffer + 20; - c->frag = 0x40 >> 3u; /* off = 64 */ - - /* Case 1: Empty fragments tree */ - ipv4_cur_frag_id = 0; - timer_add_called = 0; - /* make sure tree is empty */ - fail_if(!pico_tree_empty(&ipv4_fragments)); - - pico_ipv4_process_frag(hdr, a, TESTPROTO); - fail_if(ipv4_cur_frag_id != TESTID); - fail_if(timer_add_called != 1); - fail_if(pico_tree_empty(&ipv4_fragments)); - /* make sure we added the fragment to the tree */ - fail_if(((struct pico_frame *)pico_tree_first(&ipv4_fragments))->buffer != a->buffer); - - /* Case 2: Adding second fragment */ - timer_add_called = 0; - pico_ipv4_process_frag(hdr, b, TESTPROTO); - fail_if(ipv4_cur_frag_id != TESTID); - fail_if(timer_add_called != 0); - fail_if(pico_tree_empty(&ipv4_fragments)); - /* make sure we added the fragment to the tree */ - fail_if(((struct pico_frame *)pico_tree_last(&ipv4_fragments))->buffer != b->buffer); - - /* Case 3: Adding final fragment */ - timer_cancel_called = 0; - transport_recv_called = 0; - buffer_len_transport_receive = 0; - pico_ipv4_process_frag(hdr, c, TESTPROTO); - fail_if(ipv4_cur_frag_id != TESTID); - fail_if(timer_cancel_called != 1); - fail_if(transport_recv_called != 1); - fail_if(buffer_len_transport_receive != 96 + PICO_SIZE_IP4HDR); - /* Everything was received, tree should be empty */ - fail_if(!pico_tree_empty(&ipv4_fragments)); - - /* Cleanup */ - pico_fragments_empty_tree(&ipv4_fragments); - pico_frame_discard(a); - pico_frame_discard(b); - pico_frame_discard(c); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_ipv6_process_frag = tcase_create("Unit test for pico_ipv6_process_frag"); - TCase *TCase_pico_ipv4_process_frag = tcase_create("Unit test for pico_ipv4_process_frag"); - - TCase *TCase_pico_fragments_reassemble = tcase_create("Unit test for pico_fragments_reassemble"); - TCase *TCase_pico_fragments_get_offset = tcase_create("Unit test for pico_fragments_get_offset"); - TCase *TCase_pico_fragments_get_more_flag = tcase_create("Unit test for pico_fragments_get_more_flag"); - TCase *TCase_pico_fragments_get_header_length = tcase_create("Unit test for pico_fragments_get_header_length"); - - TCase *TCase_pico_fragments_empty_tree = tcase_create("Unit test for pico_fragments_empty_tree"); - TCase *TCase_pico_fragments_send_notify = tcase_create("Unit test for pico_fragments_send_notify"); - TCase *TCase_pico_ipv6_frag_compare = tcase_create("Unit test for pico_ipv6_frag_compare"); - TCase *TCase_pico_ipv4_frag_compare = tcase_create("Unit test for pico_ipv4_frag_compare"); - TCase *TCase_pico_ipv6_fragments_complete = tcase_create("Unit test for pico_ipv6_fragments_complete"); - TCase *TCase_pico_ipv4_fragments_complete = tcase_create("Unit test for pico_ipv4_fragments_complete"); - TCase *TCase_pico_fragments_complete = tcase_create("Unit test for pico_fragments_complete"); - TCase *TCase_pico_fragments_check_complete = tcase_create("Unit test for pico_fragments_check_complete"); - TCase *TCase_pico_frag_expire = tcase_create("Unit test for pico_frag_expire"); - TCase *TCase_pico_ipv6_frag_timer_on = tcase_create("Unit test for pico_ipv6_frag_timer_on"); - TCase *TCase_pico_ipv4_frag_timer_on = tcase_create("Unit test for pico_ipv4_frag_timer_on"); - TCase *TCase_pico_ipv6_frag_match = tcase_create("Unit test for pico_ipv6_frag_match"); - TCase *TCase_pico_ipv4_frag_match = tcase_create("Unit test for pico_ipv4_frag_match"); - - tcase_add_test(TCase_pico_ipv4_process_frag, tc_pico_ipv4_process_frag); - suite_add_tcase(s, TCase_pico_ipv4_process_frag); - tcase_add_test(TCase_pico_ipv6_process_frag, tc_pico_ipv6_process_frag); - suite_add_tcase(s, TCase_pico_ipv6_process_frag); - tcase_add_test(TCase_pico_fragments_reassemble, tc_pico_fragments_reassemble); - suite_add_tcase(s, TCase_pico_fragments_reassemble); - tcase_add_test(TCase_pico_fragments_get_offset, tc_pico_fragments_get_offset); - suite_add_tcase(s, TCase_pico_fragments_get_offset); - tcase_add_test(TCase_pico_fragments_get_more_flag, tc_pico_fragments_get_more_flag); - suite_add_tcase(s, TCase_pico_fragments_get_more_flag); - tcase_add_test(TCase_pico_fragments_get_header_length, tc_pico_fragments_get_header_length); - suite_add_tcase(s, TCase_pico_fragments_get_header_length); - tcase_add_test(TCase_pico_fragments_send_notify, tc_pico_fragments_send_notify); - suite_add_tcase(s, TCase_pico_fragments_send_notify); - tcase_add_test(TCase_pico_fragments_empty_tree, tc_pico_fragments_empty_tree); - suite_add_tcase(s, TCase_pico_fragments_empty_tree); - tcase_add_test(TCase_pico_ipv6_frag_compare, tc_pico_ipv6_frag_compare); - suite_add_tcase(s, TCase_pico_ipv6_frag_compare); - tcase_add_test(TCase_pico_ipv4_frag_compare, tc_pico_ipv4_frag_compare); - suite_add_tcase(s, TCase_pico_ipv4_frag_compare); - tcase_add_test(TCase_pico_ipv6_fragments_complete, tc_pico_ipv6_fragments_complete); - suite_add_tcase(s, TCase_pico_ipv6_fragments_complete); - tcase_add_test(TCase_pico_ipv4_fragments_complete, tc_pico_ipv4_fragments_complete); - suite_add_tcase(s, TCase_pico_ipv4_fragments_complete); - tcase_add_test(TCase_pico_fragments_complete, tc_pico_fragments_complete); - suite_add_tcase(s, TCase_pico_fragments_complete); - tcase_add_test(TCase_pico_fragments_check_complete, tc_pico_fragments_check_complete); - suite_add_tcase(s, TCase_pico_fragments_check_complete); - tcase_add_test(TCase_pico_frag_expire, tc_pico_frag_expire); - suite_add_tcase(s, TCase_pico_frag_expire); - tcase_add_test(TCase_pico_ipv6_frag_timer_on, tc_pico_ipv6_frag_timer_on); - suite_add_tcase(s, TCase_pico_ipv6_frag_timer_on); - tcase_add_test(TCase_pico_ipv4_frag_timer_on, tc_pico_ipv4_frag_timer_on); - suite_add_tcase(s, TCase_pico_ipv4_frag_timer_on); - tcase_add_test(TCase_pico_ipv6_frag_match, tc_pico_ipv6_frag_match); - suite_add_tcase(s, TCase_pico_ipv6_frag_match); - tcase_add_test(TCase_pico_ipv4_frag_match, tc_pico_ipv4_frag_match); - suite_add_tcase(s, TCase_pico_ipv4_frag_match); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_frame.c b/ext/picotcp/test/unit/modunit_pico_frame.c deleted file mode 100644 index 557d6c7..0000000 --- a/ext/picotcp/test/unit/modunit_pico_frame.c +++ /dev/null @@ -1,274 +0,0 @@ -#include "pico_config.h" -#include "pico_protocol.h" -#include "pico_frame.h" -#include "stack/pico_frame.c" -#include "check.h" - -volatile pico_err_t pico_err; - -#define FRAME_SIZE 1000 - -Suite *pico_suite(void); - -START_TEST(tc_pico_frame_alloc_discard) -{ - struct pico_frame *f = pico_frame_alloc(FRAME_SIZE); - - /* Test consistency */ - fail_if(!f); - fail_if(!f->buffer); - fail_if(!f->usage_count); - fail_if(*f->usage_count != 1); - fail_if(f->start != f->buffer); - fail_if(f->len != f->buffer_len); - fail_if(f->len != FRAME_SIZE); - pico_frame_discard(f); - - /* Test empty discard */ - pico_frame_discard(NULL); - -#ifdef PICO_FAULTY - printf("Testing with faulty memory in frame_alloc (1)\n"); - pico_set_mm_failure(1); - f = pico_frame_alloc(FRAME_SIZE); - fail_if(f); - - printf("Testing with faulty memory in frame_alloc (2)\n"); - pico_set_mm_failure(2); - f = pico_frame_alloc(FRAME_SIZE); - fail_if(f); - - printf("Testing with faulty memory in frame_do_alloc, with external buffer, failing to allocate usage_count \n"); - pico_set_mm_failure(2); - f = pico_frame_do_alloc(FRAME_SIZE, 1, 1); - fail_if(f); -#endif - printf("Testing frame_do_alloc, with invalid flags combination\n"); - f = pico_frame_do_alloc(FRAME_SIZE, 0, 1); - fail_if(f); - -} -END_TEST - -START_TEST(tc_pico_frame_grow_head) -{ - struct pico_frame *f = pico_frame_alloc(3); - struct pico_frame *f2 = pico_frame_alloc(0); - int ret = 0; - uint8_t buf[6] = { 0, 0, 0, 'a', 'b', 'c'}; - - /* I don't care about usage_count, it's tested 'pico_frame_grow' */ - fail_if(pico_frame_grow_head(f, 2) == 0); - - /* Check for dereferencing OOB */ - fail_if(pico_frame_grow_head(f2, 2) == -1); - f2->net_hdr[0] = 1; - - f->net_hdr = f->buffer; - f->net_len = 3; - f->net_hdr[0] = 'a'; - f->net_hdr[1] = 'b'; - f->net_hdr[2] = 'c'; - - /* Try to grow head */ - ret = pico_frame_grow_head(f, 6); - fail_if(ret != 0); - fail_unless(0 == memcmp(f->buffer, buf, f->buffer_len)); - fail_unless(3 == f->net_hdr - f->buffer); - - f->datalink_hdr = f->net_hdr - 3; - f->datalink_hdr[0] = 1; -} -END_TEST - -START_TEST(tc_pico_frame_grow) -{ - struct pico_frame *f = pico_frame_alloc(3); - struct pico_frame *f2 = pico_frame_alloc(0); - fail_if(f->buffer_len != 3); - /* Ensure that the usage_count starts at byte 4, for good alignment */ - fail_if(((void*)f->usage_count - (void *)f->buffer) != 4); - - ((uint8_t *)f->buffer)[0] = 'a'; - ((uint8_t *)f->buffer)[1] = 'b'; - ((uint8_t *)f->buffer)[2] = 'c'; - *f->usage_count = 12; - - - /* First, the failing cases. */ - fail_if(pico_frame_grow(NULL, 30) == 0); - fail_if(pico_frame_grow(f, 2) == 0); - f->flags = 0; - - /* Check for dereferencing OOB */ - fail_if(pico_frame_grow(f2, 3) != 0); - f2->net_hdr[0] = 1; - f2->net_hdr[1] = 2; - - pico_set_mm_failure(1); - fail_if(pico_frame_grow(f, 21) == 0); - - /* Now, the good one. */ - fail_if(pico_frame_grow(f, 21) != 0); - fail_if(f->buffer_len != 21); - fail_if(((void *)f->usage_count - (void *)f->buffer) != 24); - - - fail_if(((uint8_t *)f->buffer)[0] != 'a'); - fail_if(((uint8_t *)f->buffer)[1] != 'b'); - fail_if(((uint8_t *)f->buffer)[2] != 'c'); - fail_if(*f->usage_count != 12); - - *f->usage_count = 1; - pico_frame_discard(f); - - f = pico_frame_alloc_skeleton(10, 1); - fail_if(!f); - fail_if(f->buffer); - fail_if(!f->flags); - f->buffer = PICO_ZALLOC(10); - - fail_if(pico_frame_grow(f, 22) != 0); - fail_if (f->flags); - pico_frame_discard(f); - -} -END_TEST - -START_TEST(tc_pico_frame_copy) -{ - struct pico_frame *f = pico_frame_alloc(FRAME_SIZE); - struct pico_frame *c1, *c2, *c3; - (void)c3; - fail_if(!f); - fail_if(!f->buffer); - fail_if(*f->usage_count != 1); - - /* First copy */ - c1 = pico_frame_copy(f); - fail_if(!c1); - fail_if(!c1->buffer); - fail_if(!c1->usage_count); - - fail_if (c1->buffer != f->buffer); - fail_if(c1->usage_count != f->usage_count); - fail_if(*c1->usage_count != 2); - fail_if(*f->usage_count != 2); - fail_if(c1->start != c1->buffer); - fail_if(c1->len != c1->buffer_len); - fail_if(c1->len != FRAME_SIZE); - - /* Second copy */ - c2 = pico_frame_copy(f); - fail_if (c2->buffer != f->buffer); - fail_if(c2->usage_count != f->usage_count); - fail_if(*c2->usage_count != 3); - fail_if(*f->usage_count != 3); - fail_if(c2->start != c2->buffer); - fail_if(c2->len != c2->buffer_len); - fail_if(c2->len != FRAME_SIZE); - - -#ifdef PICO_FAULTY - printf("Testing with faulty memory in frame_copy (1)\n"); - pico_set_mm_failure(1); - c3 = pico_frame_copy(f); - fail_if(c3); - fail_if(!f); -#endif - - /* Discard 1 */ - pico_frame_discard(c1); - fail_if(*f->usage_count != 2); - - /* Discard 2 */ - pico_frame_discard(c2); - fail_if(*f->usage_count != 1); - - pico_frame_discard(f); - -} -END_TEST - -START_TEST(tc_pico_frame_deepcopy) -{ - struct pico_frame *f = pico_frame_alloc(FRAME_SIZE); - struct pico_frame *dc = pico_frame_deepcopy(f); - fail_if(*f->usage_count != 1); - fail_if(*dc->usage_count != 1); - fail_if(dc->buffer == f->buffer); -#ifdef PICO_FAULTY - printf("Testing with faulty memory in frame_deepcopy (1)\n"); - pico_set_mm_failure(1); - dc = pico_frame_deepcopy(f); - fail_if(dc); - fail_if(!f); -#endif -} -END_TEST - -START_TEST(tc_pico_is_digit) -{ - fail_if(pico_is_digit('a')); - fail_if(pico_is_digit('Z')); - fail_if(pico_is_digit('\0')); - fail_if(pico_is_digit('\n')); - fail_if(pico_is_digit('0' - 1)); - fail_if(pico_is_digit('9' + 1)); - fail_unless(pico_is_digit('0')); - fail_unless(pico_is_digit('9')); -} -END_TEST - - -START_TEST(tc_pico_is_hex) -{ - fail_if(pico_is_hex('g')); - fail_if(pico_is_hex('Z')); - fail_if(pico_is_hex('\0')); - fail_if(pico_is_hex('\n')); - fail_if(pico_is_hex('0' - 1)); - fail_if(pico_is_hex('f' + 1)); - fail_if(pico_is_hex('F' + 1)); - fail_unless(pico_is_hex('0')); - fail_unless(pico_is_hex('f')); - fail_unless(pico_is_hex('A')); - fail_unless(pico_is_hex('F')); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("pico_frame.c"); - TCase *TCase_pico_frame_alloc_discard = tcase_create("Unit test for pico_frame_alloc_discard"); - TCase *TCase_pico_frame_copy = tcase_create("Unit test for pico_frame_copy"); - TCase *TCase_pico_frame_grow = tcase_create("Unit test for pico_frame_grow"); - TCase *TCase_pico_frame_grow_head = tcase_create("Unit test for pico_frame_grow_head"); - TCase *TCase_pico_frame_deepcopy = tcase_create("Unit test for pico_frame_deepcopy"); - TCase *TCase_pico_is_digit = tcase_create("Unit test for pico_is_digit"); - TCase *TCase_pico_is_hex = tcase_create("Unit test for pico_is_hex"); - tcase_add_test(TCase_pico_frame_alloc_discard, tc_pico_frame_alloc_discard); - tcase_add_test(TCase_pico_frame_copy, tc_pico_frame_copy); - tcase_add_test(TCase_pico_frame_grow, tc_pico_frame_grow); - tcase_add_test(TCase_pico_frame_grow_head, tc_pico_frame_grow_head); - tcase_add_test(TCase_pico_frame_deepcopy, tc_pico_frame_deepcopy); - tcase_add_test(TCase_pico_is_digit, tc_pico_is_digit); - tcase_add_test(TCase_pico_is_hex, tc_pico_is_hex); - suite_add_tcase(s, TCase_pico_frame_alloc_discard); - suite_add_tcase(s, TCase_pico_frame_copy); - suite_add_tcase(s, TCase_pico_frame_grow); - suite_add_tcase(s, TCase_pico_frame_grow_head); - suite_add_tcase(s, TCase_pico_frame_deepcopy); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_hotplug_detection.c b/ext/picotcp/test/unit/modunit_pico_hotplug_detection.c deleted file mode 100644 index cbcc32b..0000000 --- a/ext/picotcp/test/unit/modunit_pico_hotplug_detection.c +++ /dev/null @@ -1,192 +0,0 @@ -#include "pico_hotplug_detection.h" -#include "pico_tree.h" -#include "pico_device.h" -#include "modules/pico_hotplug_detection.c" -#include "check.h" -#include "pico_dev_null.c" - -Suite *pico_suite(void); -void cb_one(struct pico_device *dev, int event); -void cb_two(struct pico_device *dev, int event); -int link_state_a(struct pico_device *self); -int link_state_b(struct pico_device *self); - -/* stubs for timer */ -static int8_t timer_active = 0; -void (*timer_cb_function)(pico_time, void *); -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(expire); - IGNORE_PARAMETER(arg); - - timer_active++; - timer_cb_function = timer; - - return 123; -} - -void pico_timer_cancel(uint32_t id) -{ - timer_active--; - fail_if(id != 123); -} - -/* callbacks for testing */ -uint32_t cb_one_cntr = 0; -int cb_one_last_event = 0; -void cb_one(struct pico_device *dev, int event) -{ - IGNORE_PARAMETER(dev); - - cb_one_cntr++; - cb_one_last_event = event; -} -uint32_t cb_two_cntr = 0; -int cb_two_last_event = 0; -void cb_two(struct pico_device *dev, int event) -{ - IGNORE_PARAMETER(dev); - - cb_two_cntr++; - cb_two_last_event = event; -} - -/* link state functions for the testing devices */ -int state_a = 0; -int link_state_a(struct pico_device *self) -{ - IGNORE_PARAMETER(self); - return state_a; -} - -int state_b = 0; -int link_state_b(struct pico_device *self) -{ - IGNORE_PARAMETER(self); - return state_b; -} - - -START_TEST(tc_pico_hotplug_reg_dereg) -{ - /* create some devices */ - struct pico_device *dev_a, *dev_b; - dev_a = pico_null_create("dummy1"); - dev_b = pico_null_create("dummy2"); - - dev_a->link_state = &link_state_a; - dev_b->link_state = &link_state_b; - - /* add some function pointers to be called */ - pico_hotplug_register(dev_a, &cb_one); - fail_unless(timer_active == 1); - pico_hotplug_register(dev_a, &cb_two); - pico_hotplug_register(dev_b, &cb_two); - fail_unless(timer_active == 1); - - /* remove function pointers */ - pico_hotplug_deregister(dev_a, &cb_one); - pico_hotplug_deregister(dev_a, &cb_two); - pico_hotplug_deregister(dev_b, &cb_two); - - /* check that our tree is empty at the end */ - fail_unless(pico_tree_empty(&Hotplug_device_tree)); - - /* register functions multiple times */ - pico_hotplug_register(dev_a, &cb_one); - pico_hotplug_register(dev_a, &cb_one); - pico_hotplug_register(dev_a, &cb_two); - pico_hotplug_register(dev_a, &cb_two); - pico_hotplug_register(dev_b, &cb_two); - pico_hotplug_register(dev_b, &cb_two); - - /* remove function pointers once */ - pico_hotplug_deregister(dev_a, &cb_one); - pico_hotplug_deregister(dev_a, &cb_two); - fail_unless(timer_active == 1); - pico_hotplug_deregister(dev_b, &cb_two); - fail_unless(timer_active == 0); - - /* check that our tree is empty at the end */ - fail_unless(pico_tree_empty(&Hotplug_device_tree)); -} -END_TEST - -START_TEST(tc_pico_hotplug_callbacks) -{ - /* create some devices */ - struct pico_device *dev_a, *dev_b; - - dev_a = pico_null_create("dummy1"); - dev_b = pico_null_create("dummy2"); - - dev_a->link_state = &link_state_a; - dev_b->link_state = &link_state_b; - - /* add some function pointers to be called */ - pico_hotplug_register(dev_a, &cb_one); - pico_hotplug_register(dev_a, &cb_two); - pico_hotplug_register(dev_b, &cb_two); - - fail_unless(timer_active == 1); - - timer_active = 0; - timer_cb_function(0, NULL); - fail_unless(timer_active == 1); - fail_unless(cb_one_cntr == 1); - fail_unless(cb_two_cntr == 2); - - state_a = 1; - timer_active = 0; - timer_cb_function(0, NULL); - fail_unless(timer_active == 1); - fail_unless(cb_one_cntr == 2); - fail_unless(cb_one_last_event == PICO_HOTPLUG_EVENT_UP ); - fail_unless(cb_two_cntr == 3); - fail_unless(cb_two_last_event == PICO_HOTPLUG_EVENT_UP ); - - state_b = 1; - timer_active = 0; - timer_cb_function(0, NULL); - fail_unless(timer_active == 1); - fail_unless(cb_one_cntr == 2); - fail_unless(cb_one_last_event == PICO_HOTPLUG_EVENT_UP ); - fail_unless(cb_two_cntr == 4); - fail_unless(cb_two_last_event == PICO_HOTPLUG_EVENT_UP ); - - state_a = 0; - state_b = 0; - timer_active = 0; - timer_cb_function(0, NULL); - fail_unless(timer_active == 1); - fail_unless(cb_one_cntr == 3); - fail_unless(cb_one_last_event == PICO_HOTPLUG_EVENT_DOWN ); - fail_unless(cb_two_cntr == 6); - fail_unless(cb_two_last_event == PICO_HOTPLUG_EVENT_DOWN ); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_hotplug_reg_dereg = tcase_create("Unit test for pico_hotplug_reg_dereg"); - TCase *TCase_pico_hotplug_callbacks = tcase_create("Unit test for pico_hotplug_callbacks"); - - tcase_add_test(TCase_pico_hotplug_reg_dereg, tc_pico_hotplug_reg_dereg); - suite_add_tcase(s, TCase_pico_hotplug_reg_dereg); - tcase_add_test(TCase_pico_hotplug_callbacks, tc_pico_hotplug_callbacks); - suite_add_tcase(s, TCase_pico_hotplug_callbacks); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_igmp.c b/ext/picotcp/test/unit/modunit_pico_igmp.c deleted file mode 100644 index bfc7c22..0000000 --- a/ext/picotcp/test/unit/modunit_pico_igmp.c +++ /dev/null @@ -1,359 +0,0 @@ -#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" -#include "modules/pico_igmp.c" -#include "check.h" -#include "pico_dev_null.c" - -Suite *pico_suite(void); -void mock_callback(struct igmp_timer *t); - -static uint32_t timers_added = 0; -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(expire); - IGNORE_PARAMETER(timer); - IGNORE_PARAMETER(arg); - return ++timers_added; -} - -void mock_callback(struct igmp_timer *t) -{ - IGNORE_PARAMETER(t); -} -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; -} -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; -} -static PICO_TREE_DECLARE(_MCASTFilter, mcast_filter_cmp); -START_TEST(tc_pico_igmp_report_expired) -{ - struct igmp_timer *t = PICO_ZALLOC(sizeof(struct igmp_timer)); - struct pico_ip4 zero = {0}; - t->mcast_link = zero; - t->mcast_group = zero; - /* void function, just check for side effects */ - pico_igmp_report_expired(t); -} -END_TEST -START_TEST(tc_igmpt_type_compare) -{ - struct igmp_timer a; - struct igmp_timer b; - a.type = 1; - b.type = 2; - fail_if(igmpt_type_compare(&a, &b) != -1); - fail_if(igmpt_type_compare(&b, &a) != 1); - fail_if(igmp_timer_cmp(&b, &a) != 1); -} -END_TEST -START_TEST(tc_pico_igmp_state_change) -{ - struct pico_ip4 mcast_link, mcast_group; - pico_string_to_ipv4("192.168.1.1", &mcast_link.addr); - pico_string_to_ipv4("224.7.7.7", &mcast_group.addr); - fail_if(pico_igmp_state_change(&mcast_link, &mcast_group, 0, NULL, 99) != -1); - fail_if(pico_igmp_state_change(&mcast_link, &mcast_group, 0, NULL, PICO_IGMP_STATE_CREATE) != 0); -} -END_TEST -START_TEST(tc_pico_igmp_timer_expired) -{ - struct igmp_timer *t, *s; - t = PICO_ZALLOC(sizeof(struct igmp_timer)); - t->stopped = IGMP_TIMER_STOPPED; - t->type = 0; - pico_string_to_ipv4("192.168.1.1", &t->mcast_link.addr); - pico_string_to_ipv4("244.7.7.7", &t->mcast_group.addr); - /* void function, just check for side effects */ - pico_igmp_timer_expired(0, (void *)t); - pico_tree_insert(&IGMPTimers, t); - s = PICO_ZALLOC(sizeof(struct igmp_timer)); - memcpy(s,t,sizeof(struct igmp_timer)); // t will be freed next test - pico_igmp_timer_expired(0, (void *)t); /* t is freed here */ - s->stopped++; - s->start = PICO_TIME_MS()*2; - s->type++; - pico_tree_insert(&IGMPTimers, s); - t = PICO_ZALLOC(sizeof(struct igmp_timer)); - memcpy(t,s,sizeof(struct igmp_timer)); // s will be freed next test - pico_igmp_timer_expired(0, (void *)s); /* s is freed here */ - t->callback = mock_callback; - pico_igmp_timer_expired(0, (void *)t); -} -END_TEST -START_TEST(tc_pico_igmp_v2querier_expired) -{ - struct igmp_timer *t = PICO_ZALLOC(sizeof(struct igmp_timer)); - struct pico_ip4 addr = {0}; - struct pico_device *dev = pico_null_create("dummy2"); - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_frame)); - t->f = f; - pico_string_to_ipv4("192.168.1.1", &(addr.addr)); - /* void function, just check for side effects */ - /* No link */ - pico_igmp_v2querier_expired(t); - f->dev = dev; - pico_ipv4_link_add(dev, addr, addr); - pico_igmp_v2querier_expired(t); -} -END_TEST -START_TEST(tc_pico_igmp_delete_parameter) -{ - struct mcast_parameters p; - fail_if(pico_igmp_delete_parameter(&p) != -1); -} -END_TEST -START_TEST(tc_pico_igmp_process_in) -{ - struct mcast_parameters *p; - struct pico_device *dev = pico_null_create("dummy3"); - struct pico_ipv4_link *link; - uint8_t i, j, _i, _j; - int result; - struct pico_mcast_group g; - /* Building example frame */ - p = PICO_ZALLOC(sizeof(struct mcast_parameters)); - pico_string_to_ipv4("192.168.1.1", &p->mcast_link.ip4.addr); - pico_string_to_ipv4("244.7.7.7", &p->mcast_group.ip4.addr); - /* no link */ - fail_if(pico_igmp_generate_report(p) != -1); - - pico_ipv4_link_add(dev, p->mcast_link.ip4, p->mcast_link.ip4); - link = pico_ipv4_link_get(&p->mcast_link.ip4); - link->mcast_compatibility = PICO_IGMPV2; - g.mcast_addr.ip4 = p->mcast_group.ip4; - g.MCASTSources.root = &LEAF; - g.MCASTSources.compare = mcast_sources_cmp; - /* No mcastsources tree */ - link->mcast_compatibility = PICO_IGMPV3; - fail_if(pico_igmp_generate_report(p) != -1); - pico_tree_insert(link->MCASTGroups, &g); - pico_tree_insert(&IGMPParameters, p); - - link->mcast_compatibility = 99; - fail_if(pico_igmp_generate_report(p) != -1); - link->mcast_compatibility = PICO_IGMPV2; - fail_if(pico_igmp_generate_report(p) != 0); - link->mcast_compatibility = PICO_IGMPV3; - for(_j = 0; _j < 3; _j++) { /* FILTER */ - (_j == 2) ? (result = -1) : (result = 0); - for(_i = 0; _i < 3; _i++) { /* FILTER */ - if(_i == 2) result = -1; - - for(i = 0; i < 3; i++) { /* STATES */ - for(j = 0; j < 6; j++) { /* EVENTS */ - p->MCASTFilter = &_MCASTFilter; - p->filter_mode = _i; - g.filter_mode = _j; - if(p->event == IGMP_EVENT_DELETE_GROUP || p->event == IGMP_EVENT_QUERY_RECV) - p->event++; - - fail_if(pico_igmp_generate_report(p) != result); - p->state = i; - p->event = j; - if(result != -1 && p->f) /* in some combinations, no frame is created */ - fail_if(pico_igmp_process_in(NULL, p->f) != 0); - } - } - } - } -} -END_TEST -START_TEST(tc_pico_igmp_find_parameter) -{ - struct pico_ip4 mcast_link, mcast_group; - struct mcast_parameters test = { - 0 - }; - fail_if(pico_igmp_find_parameter(NULL, NULL) != NULL); - pico_string_to_ipv4("192.168.1.1", &mcast_link.addr); - fail_if(pico_igmp_find_parameter(&mcast_link, NULL) != NULL); - pico_string_to_ipv4("192.168.1.2", &mcast_group.addr); - fail_if(pico_igmp_find_parameter(&mcast_link, &mcast_group) != NULL); - test.mcast_link.ip4 = mcast_link; - test.mcast_group.ip4 = mcast_group; - pico_tree_insert(&IGMPParameters, &test); - - fail_if(pico_igmp_find_parameter(&mcast_link, &mcast_group) == NULL); -} -END_TEST -START_TEST(tc_pico_igmp_compatibility_mode) -{ - struct pico_frame *f; - struct pico_device *dev = pico_null_create("dummy1"); - struct pico_ip4 addr; - struct pico_ipv4_hdr *hdr; - struct igmp_message *query; - uint8_t ihl = 24; - f = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (0 * sizeof(struct pico_ip4))); - pico_string_to_ipv4("192.168.1.2", &addr.addr); - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - ihl = (uint8_t)((hdr->vhl & 0x0F) * 4); /* IHL is in 32bit words */ - query = (struct igmp_message *) f->transport_hdr; - /* No link */ - fail_if(pico_igmp_compatibility_mode(f) != -1); - pico_ipv4_link_add(dev, addr, addr); - f->dev = dev; - /* Igmpv3 query */ - hdr->len = short_be((uint16_t)(12 + ihl)); - fail_if(pico_igmp_compatibility_mode(f) != 0); - /* Igmpv2 query */ - hdr->len = short_be((uint16_t)(8 + ihl)); - query->max_resp_time = 0; - fail_if(pico_igmp_compatibility_mode(f) == 0); - query->max_resp_time = 1; - fail_if(pico_igmp_compatibility_mode(f) != 0); - /* Invalid Query */ - hdr->len = short_be((uint16_t)(9 + ihl)); - fail_if(pico_igmp_compatibility_mode(f) == 0); -} -END_TEST -START_TEST(tc_pico_igmp_analyse_packet) -{ - struct pico_frame *f; - struct pico_device *dev = pico_null_create("dummy0"); - struct pico_ip4 addr; - struct igmp_message *igmp; - f = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, sizeof(struct igmp_message)); - pico_string_to_ipv4("192.168.1.1", &addr.addr); - /* No link */ - fail_if(pico_igmp_analyse_packet(f) != NULL); - pico_ipv4_link_add(dev, addr, addr); - f->dev = dev; - - igmp = (struct igmp_message *) (f->transport_hdr); - igmp->type = 0; - /* wrong type */ - fail_if(pico_igmp_analyse_packet(f) != NULL); - - /* all correct */ - igmp->type = IGMP_TYPE_MEM_QUERY; - fail_if(pico_igmp_analyse_packet(f) == NULL); - igmp->type = IGMP_TYPE_MEM_REPORT_V1; - fail_if(pico_igmp_analyse_packet(f) == NULL); - igmp->type = IGMP_TYPE_MEM_REPORT_V2; - fail_if(pico_igmp_analyse_packet(f) == NULL); - igmp->type = IGMP_TYPE_MEM_REPORT_V3; - fail_if(pico_igmp_analyse_packet(f) == NULL); -} -END_TEST -START_TEST(tc_pico_igmp_discard) -{ - /* TODO */ -} -END_TEST -START_TEST(tc_srst) -{ - struct mcast_parameters p; - struct pico_device *dev = pico_null_create("dummy0"); - struct pico_ipv4_link *link; - - pico_string_to_ipv4("192.168.1.1", &p.mcast_link.ip4.addr); - /* no link */ - fail_if(srst(&p) != -1); - pico_ipv4_link_add(dev, p.mcast_link.ip4, p.mcast_link.ip4); - link = pico_ipv4_link_get(&p.mcast_link.ip4); - /* Not supported protocol for this call */ - link->mcast_compatibility = PICO_IGMPV2; - fail_if(srst(&p) != -1); - link->mcast_compatibility = PICO_IGMPV3; - fail_if(srst(&p) != -1); -} -END_TEST -START_TEST(tc_stcl) -{ - struct igmp_timer *t = PICO_ZALLOC(sizeof(struct igmp_timer)); - struct mcast_parameters p; - - pico_string_to_ipv4("192.168.1.10", &t->mcast_link.addr); - pico_string_to_ipv4("244.7.7.7", &t->mcast_group.addr); - p.mcast_link.ip4 = t->mcast_link; - p.mcast_group.ip4 = t->mcast_group; - t->type = IGMP_TIMER_GROUP_REPORT; - /* not in tree */ - fail_if(stcl(&p) != -1); - pico_igmp_timer_start(t); - fail_if(stcl(&p) != 0); -} -END_TEST - -Suite *pico_suite(void) -{ - - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_igmp_report_expired = tcase_create("Unit test for pico_igmp_report_expired"); - TCase *TCase_igmpt_type_compare = tcase_create("Unit test for igmpt_type_compare"); - TCase *TCase_pico_igmp_analyse_packet = tcase_create("Unit test for pico_igmp_analyse_packet"); - TCase *TCase_pico_igmp_discard = tcase_create("Unit test for pico_igmp_discard"); - TCase *TCase_pico_igmp_compatibility_mode = tcase_create("Unit test for pico_igmp_compatibility"); - TCase *TCase_pico_igmp_state_change = tcase_create("Unit test for pico_igmp_state_change"); - TCase *TCase_pico_igmp_process_in = tcase_create("Unit test for pico_igmp_process_in"); - TCase *TCase_pico_igmp_timer_expired = tcase_create("Unit test for pico_igmp_timer_expired"); - TCase *TCase_pico_igmp_delete_parameter = tcase_create("Unit test for pico_igmp_delete_parameter"); - TCase *TCase_pico_igmp_find_parameter = tcase_create("Unit test for pico_igmp_find_parameter"); - TCase *TCase_stcl = tcase_create("Unit test for stcl"); - TCase *TCase_srst = tcase_create("Unit test for srst"); - TCase *TCase_pico_igmp_v2querier_expired = tcase_create("Unit test for pico_igmp_v2_querier_expired"); - - tcase_add_test(TCase_pico_igmp_report_expired, tc_pico_igmp_report_expired); - suite_add_tcase(s, TCase_pico_igmp_report_expired); - tcase_add_test(TCase_igmpt_type_compare, tc_igmpt_type_compare); - suite_add_tcase(s, TCase_igmpt_type_compare); - tcase_add_test(TCase_pico_igmp_analyse_packet, tc_pico_igmp_analyse_packet); - suite_add_tcase(s, TCase_pico_igmp_analyse_packet); - tcase_add_test(TCase_pico_igmp_discard, tc_pico_igmp_discard); - suite_add_tcase(s, TCase_pico_igmp_discard); - tcase_add_test(TCase_pico_igmp_compatibility_mode, tc_pico_igmp_compatibility_mode); - suite_add_tcase(s, TCase_pico_igmp_compatibility_mode); - suite_add_tcase(s, TCase_pico_igmp_state_change); - tcase_add_test(TCase_pico_igmp_state_change, tc_pico_igmp_state_change); - suite_add_tcase(s, TCase_pico_igmp_process_in); - tcase_add_test(TCase_pico_igmp_process_in, tc_pico_igmp_process_in); - suite_add_tcase(s, TCase_pico_igmp_timer_expired); - tcase_add_test(TCase_pico_igmp_timer_expired, tc_pico_igmp_timer_expired); - suite_add_tcase(s, TCase_pico_igmp_delete_parameter); - tcase_add_test(TCase_pico_igmp_delete_parameter, tc_pico_igmp_delete_parameter); - suite_add_tcase(s, TCase_pico_igmp_find_parameter); - tcase_add_test(TCase_pico_igmp_find_parameter, tc_pico_igmp_find_parameter); - suite_add_tcase(s, TCase_stcl); - tcase_add_test(TCase_stcl, tc_stcl); - suite_add_tcase(s, TCase_srst); - tcase_add_test(TCase_srst, tc_srst); - suite_add_tcase(s, TCase_pico_igmp_v2querier_expired); - tcase_add_test(TCase_pico_igmp_v2querier_expired, tc_pico_igmp_v2querier_expired); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_ipfilter.c b/ext/picotcp/test/unit/modunit_pico_ipfilter.c deleted file mode 100644 index bad6c68..0000000 --- a/ext/picotcp/test/unit/modunit_pico_ipfilter.c +++ /dev/null @@ -1,321 +0,0 @@ -#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" -#include "modules/pico_ipfilter.c" -#include "check.h" - -Suite *pico_suite(void); -int pico_icmp4_packet_filtered(struct pico_frame *f) -{ - (void)f; - return 0; -} - -void pico_frame_discard(struct pico_frame *f) -{ - (void)f; -} - -volatile pico_err_t pico_err; - - - -START_TEST(tc_ipfilter) -{ - uint32_t r; - struct filter_node a = { - 0 - }, b = { - 0 - }; - fail_if(filter_compare(&a, &b) != 0); - - - /* a is rule, matching packet b */ - a.filter_id = 1; - - /* check that rule is matched properly */ - fail_if(filter_match_packet_find_rule(&a, &b) != &a); - - /* a has a out port that does not match packet */ - b.out_port = 8; - a.out_port = 7; - fail_if(filter_compare(&a, &b) == 0); - - /* a matches all ports */ - a.out_port = 0; - fail_if(filter_compare(&a, &b) != 0); - - /*** NEXT TEST ***/ - - - /* a has a in port that does not match packet */ - b.in_port = 8; - a.in_port = 7; - fail_if(filter_compare(&a, &b) == 0); - - /* a matches all ports */ - a.in_port = 0; - fail_if(filter_compare(&a, &b) != 0); - - /* a matches port exactly */ - a.in_port = 0; - fail_if(filter_compare(&a, &b) != 0); - - /*** NEXT TEST ***/ - - /* a matches all out addresses */ - b.out_addr = 0x010000a0; - fail_if(filter_compare(&a, &b) != 0); - - /* a does not match b via 8-bit netmask */ - a.out_addr = 0x000000c0; - a.out_addr_netmask = 0x000000ff; - fail_if(filter_compare(&a, &b) == 0); - - /* a does not match b at all*/ - a.out_addr = 0x020000b0; - a.out_addr_netmask = 0xffffffff; - fail_if(filter_compare(&a, &b) == 0); - - /* a matches b via 8-bit netmask */ - a.out_addr = 0x000000a0; - a.out_addr_netmask = 0x000000ff; - fail_if(filter_compare(&a, &b) != 0); - - /* a matches b exactly */ - a.out_addr = 0x010000a0; - a.out_addr_netmask = 0xffffffff; - fail_if(filter_compare(&a, &b) != 0); - - /*** NEXT TEST ***/ - - /* a matches all in addresses */ - b.in_addr = 0x010000a0; - fail_if(filter_compare(&a, &b) != 0); - - /* a does not match b via 8-bit netmask */ - a.in_addr = 0x000000c0; - a.in_addr_netmask = 0x000000ff; - fail_if(filter_compare(&a, &b) == 0); - - /* a does not match b at all*/ - a.in_addr = 0x020000b0; - a.in_addr_netmask = 0xffffffff; - fail_if(filter_compare(&a, &b) == 0); - - /* a matches b via 8-bit netmask */ - a.in_addr = 0x000000a0; - a.in_addr_netmask = 0x000000ff; - fail_if(filter_compare(&a, &b) != 0); - - /* a matches b exactly */ - a.in_addr = 0x010000a0; - a.in_addr_netmask = 0xffffffff; - fail_if(filter_compare(&a, &b) != 0); - - /*** NEXT TEST ***/ - - /* a matches all protocols */ - b.proto = 4u; - fail_if(filter_compare(&a, &b) != 0); - - /* a does not match protocol */ - a.proto = 5u; - fail_if(filter_compare(&a, &b) == 0); - - /* a matches b's protocol */ - a.proto = b.proto; - fail_if(filter_compare(&a, &b) != 0); - - /*** NEXT TEST ***/ - - /* a matches all devices */ - b.fdev = (struct pico_device *) &b; - fail_if(filter_compare(&a, &b) != 0); - - /* a does not match device */ - a.fdev = (struct pico_device *)&a; - fail_if(filter_compare(&a, &b) == 0); - - /* a matches b's device */ - a.fdev = b.fdev; - fail_if(filter_compare(&a, &b) != 0); - - - /*** SAME TEST DUPLICATED WITH INVERTED ORDER OF PARAMETERS ***/ - - memset(&a, 0, sizeof(struct filter_node)); - memset(&b, 0, sizeof(struct filter_node)); - - a.filter_id = 2; - - - /* check that rule is matched properly */ - fail_if(filter_match_packet_find_rule(&b, &a) != &a); - - /* a has a out port that does not match packet */ - b.out_port = 8; - a.out_port = 7; - fail_if(filter_compare(&b, &a) == 0); - - /* a matches all ports */ - a.out_port = 0; - fail_if(filter_compare(&b, &a) != 0); - - /*** NEXT TEST ***/ - - - /* a has a in port that does not match packet */ - b.in_port = 8; - a.in_port = 7; - fail_if(filter_compare(&b, &a) == 0); - - /* a matches all ports */ - a.in_port = 0; - fail_if(filter_compare(&b, &a) != 0); - - /* a matches port exactly */ - a.in_port = 0; - fail_if(filter_compare(&b, &a) != 0); - - /*** NEXT TEST ***/ - - /* a matches all out addresses */ - b.out_addr = 0x010000a0; - fail_if(filter_compare(&b, &a) != 0); - - /* a does not match b via 8-bit netmask */ - a.out_addr = 0x000000c0; - a.out_addr_netmask = 0x000000ff; - fail_if(filter_compare(&b, &a) == 0); - - /* a does not match b at all*/ - a.out_addr = 0x020000b0; - a.out_addr_netmask = 0xffffffff; - fail_if(filter_compare(&b, &a) == 0); - - /* a matches b via 8-bit netmask */ - a.out_addr = 0x000000a0; - a.out_addr_netmask = 0x000000ff; - fail_if(filter_compare(&b, &a) != 0); - - /* a matches b exactly */ - a.out_addr = 0x010000a0; - a.out_addr_netmask = 0xffffffff; - fail_if(filter_compare(&b, &a) != 0); - - /*** NEXT TEST ***/ - - /* a matches all in addresses */ - b.in_addr = 0x010000a0; - fail_if(filter_compare(&b, &a) != 0); - - /* a does not match b via 8-bit netmask */ - a.in_addr = 0x000000c0; - a.in_addr_netmask = 0x000000ff; - fail_if(filter_compare(&b, &a) == 0); - - /* a does not match b at all*/ - a.in_addr = 0x020000b0; - a.in_addr_netmask = 0xffffffff; - fail_if(filter_compare(&b, &a) == 0); - - /* a matches b via 8-bit netmask */ - a.in_addr = 0x000000a0; - a.in_addr_netmask = 0x000000ff; - fail_if(filter_compare(&b, &a) != 0); - - /* a matches b exactly */ - a.in_addr = 0x010000a0; - a.in_addr_netmask = 0xffffffff; - fail_if(filter_compare(&b, &a) != 0); - - /*** NEXT TEST ***/ - - /* a matches all protocols */ - b.proto = 4u; - fail_if(filter_compare(&b, &a) != 0); - - /* a does not match protocol */ - a.proto = 5u; - fail_if(filter_compare(&b, &a) == 0); - - /* a matches b's protocol */ - a.proto = b.proto; - fail_if(filter_compare(&b, &a) != 0); - - /*** NEXT TEST ***/ - - /* a matches all devices */ - b.fdev = (struct pico_device *)&b; - fail_if(filter_compare(&b, &a) != 0); - - /* a does not match device */ - a.fdev = (struct pico_device *)&a; - fail_if(filter_compare(&b, &a) == 0); - - /* a matches b's device */ - a.fdev = b.fdev; - fail_if(filter_compare(&b, &a) != 0); - - - - /*********** TEST ADD FILTER **************/ - - /* - 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) - */ - - - r = pico_ipv4_filter_add(NULL, 0, NULL, NULL, NULL, NULL, 0, 0, MAX_PRIORITY + 1, 0, FILTER_DROP); - fail_if(r > 0); - - r = pico_ipv4_filter_add(NULL, 0, NULL, NULL, NULL, NULL, 0, 0, MIN_PRIORITY - 1, 0, FILTER_PRIORITY); - fail_if(r > 0); - - r = pico_ipv4_filter_add(NULL, 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0, FILTER_COUNT); - fail_if(r > 0); - -#ifdef FAULTY - pico_set_mm_failure(1); - r = pico_ipv4_filter_add(NULL, 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0, FILTER_DROP); - fail_if(r > 0); - fail_if(pico_err != PICO_ERR_ENOMEM); -#endif -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("IPfilter module"); - - TCase *TCase_ipfilter = tcase_create("Unit test for ipfilter"); - tcase_add_test(TCase_ipfilter, tc_ipfilter); - suite_add_tcase(s, TCase_ipfilter); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_ipv6_nd.c b/ext/picotcp/test/unit/modunit_pico_ipv6_nd.c deleted file mode 100644 index 435b5de..0000000 --- a/ext/picotcp/test/unit/modunit_pico_ipv6_nd.c +++ /dev/null @@ -1,289 +0,0 @@ -#include "pico_config.h" -#include "pico_tree.h" -#include "pico_ipv6_nd.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 "modules/pico_ipv6_nd.c" -#include "check.h" -#ifdef PICO_SUPPORT_IPV6 - -#undef PICO_TIME -#undef PICO_TIME_MS - -#define PICO_TIME_MS (0) -#define PICO_TIME (0) - -Suite *pico_suite(void); -START_TEST(tc_pico_nd_new_expire_time) -{ - struct pico_ipv6_neighbor n = { - 0 - }; - struct pico_device d = { {0} }; - - /* TODO: how to test these time values */ - - n.dev = &d; - - d.hostvars.retranstime = 666; - - n.state = PICO_ND_STATE_INCOMPLETE; - pico_nd_new_expire_time(&n); - - n.state = PICO_ND_STATE_REACHABLE; - pico_nd_new_expire_time(&n); - - - n.state = PICO_ND_STATE_STALE; - pico_nd_new_expire_time(&n); - - - n.state = PICO_ND_STATE_PROBE; - pico_nd_new_expire_time(&n); - -} -END_TEST -START_TEST(tc_pico_nd_queue) -{ - struct pico_ip6 addr = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; - int i; - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); - struct pico_ipv6_hdr *h = (struct pico_ipv6_hdr *) f->buffer; - f->net_hdr = (uint8_t*) h; - f->buffer[0] = 0x60; /* Ipv6 */ - memcpy(h->dst.addr, addr.addr, PICO_SIZE_IP6); - - fail_if(!f); - - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) { - fail_if(frames_queued_v6[i] != NULL); - } - pico_ipv6_nd_unreachable(&addr); - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) { - fail_if(frames_queued_v6[i] != NULL); - } - pico_ipv6_nd_postpone(f); - fail_if(frames_queued_v6[0]->buffer != f->buffer); - - pico_ipv6_nd_unreachable(&addr); - - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) { - fail_if(frames_queued_v6[i] != NULL); - } -} -END_TEST - -START_TEST(tc_pico_nd_discover) -{ - /* TODO: test this: static void pico_nd_discover(struct pico_ipv6_neighbor *n) */ -} -END_TEST -START_TEST(tc_neigh_options) -{ - /* TODO: test this: static int neigh_options(struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt) */ -} -END_TEST -START_TEST(tc_neigh_adv_complete) -{ - /* TODO: test this: static int neigh_adv_complete(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt) */ -} -END_TEST -START_TEST(tc_neigh_adv_reconfirm_router_option) -{ - /* TODO: test this: static void neigh_adv_reconfirm_router_option(struct pico_ipv6_neighbor *n, unsigned int isRouter) */ -} -END_TEST -START_TEST(tc_neigh_adv_reconfirm) -{ - /* TODO: test this: static int neigh_adv_reconfirm(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_icmp6_hdr *hdr) */ -} -END_TEST -START_TEST(tc_neigh_adv_check_solicited) -{ - /* TODO: test this: static void neigh_adv_check_solicited(struct pico_icmp6_hdr *ic6, struct pico_ipv6_neighbor *n) */ -} -END_TEST -START_TEST(tc_neigh_adv_process) -{ - /* TODO: test this: static int neigh_adv_process(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_ipv6_neighbor) -{ - /* TODO: test this: static struct pico_ipv6_neighbor *neighbor_from_sol_new(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) */ -} -END_TEST -START_TEST(tc_neighbor_from_sol) -{ - /* TODO: test this: static void neighbor_from_sol(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) */ -} -END_TEST -START_TEST(tc_neigh_sol_process) -{ - /* TODO: test this: static int neigh_sol_process(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_icmp6_initial_checks) -{ - /* TODO: test this: static int icmp6_initial_checks(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_neigh_adv_mcast_validity_checks) -{ - /* TODO: test this: static int neigh_adv_mcast_validity_check(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_neigh_sol_mcast_validity_checks) -{ - /* TODO: test this: static int neigh_sol_mcast_validity_check(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_neigh_adv_validity_checks) -{ - /* TODO: test this: static int neigh_adv_validity_checks(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_neigh_sol_validity_checks) -{ - /* TODO: test this: static int neigh_sol_validity_checks(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_neigh_adv_checks) -{ - /* TODO: test this: static int neigh_adv_checks(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_nd_router_sol_recv) -{ - /* TODO: test this: static int pico_nd_router_sol_recv(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_nd_router_adv_recv) -{ - /* TODO: test this: static int pico_nd_router_adv_recv(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_nd_neigh_sol_recv) -{ - /* TODO: test this: static int pico_nd_neigh_sol_recv(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_nd_neigh_adv_recv) -{ - /* TODO: test this: static int pico_nd_neigh_adv_recv(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_nd_redirect_recv) -{ - /* TODO: test this: static int pico_nd_redirect_recv(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_ipv6_nd_timer_callback) -{ - /* TODO: test this: static void pico_ipv6_nd_timer_callback(pico_time now, void *arg) */ -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_nd_new_expire_time = tcase_create("Unit test for pico_nd_new_expire_time"); - TCase *TCase_pico_nd_discover = tcase_create("Unit test for pico_nd_discover"); - TCase *TCase_neigh_options = tcase_create("Unit test for neigh_options"); - TCase *TCase_neigh_adv_complete = tcase_create("Unit test for neigh_adv_complete"); - TCase *TCase_neigh_adv_reconfirm_router_option = tcase_create("Unit test for neigh_adv_reconfirm_router_option"); - TCase *TCase_neigh_adv_reconfirm = tcase_create("Unit test for neigh_adv_reconfirm"); - TCase *TCase_neigh_adv_check_solicited = tcase_create("Unit test for neigh_adv_check_solicited"); - TCase *TCase_neigh_adv_process = tcase_create("Unit test for neigh_adv_process"); - TCase *TCase_pico_ipv6_neighbor = tcase_create("Unit test for pico_ipv6_neighbor"); - TCase *TCase_neighbor_from_sol = tcase_create("Unit test for neighbor_from_sol"); - TCase *TCase_neigh_sol_process = tcase_create("Unit test for neigh_sol_process"); - TCase *TCase_icmp6_initial_checks = tcase_create("Unit test for icmp6_initial_checks"); - TCase *TCase_neigh_sol_mcast_validity_checks = tcase_create("Unit test for neigh_sol_mcast_validity_checks"); - TCase *TCase_neigh_sol_validity_checks = tcase_create("Unit test for neigh_sol_validity_checks"); - TCase *TCase_neigh_adv_checks = tcase_create("Unit test for neigh_adv_checks"); - TCase *TCase_neigh_adv_validity_checks = tcase_create("Unit test for neigh_adv_validity_checks"); - TCase *TCase_neigh_adv_mcast_validity_checks = tcase_create("Unit test for neigh_adv_mcast_validity_checks"); - TCase *TCase_pico_nd_router_sol_recv = tcase_create("Unit test for pico_nd_router_sol_recv"); - TCase *TCase_pico_nd_router_adv_recv = tcase_create("Unit test for pico_nd_router_adv_recv"); - TCase *TCase_pico_nd_neigh_sol_recv = tcase_create("Unit test for pico_nd_neigh_sol_recv"); - TCase *TCase_pico_nd_neigh_adv_recv = tcase_create("Unit test for pico_nd_neigh_adv_recv"); - TCase *TCase_pico_nd_redirect_recv = tcase_create("Unit test for pico_nd_redirect_recv"); - TCase *TCase_pico_ipv6_nd_timer_callback = tcase_create("Unit test for pico_ipv6_nd_timer_callback"); - TCase *TCase_pico_nd_queue = tcase_create("Unit test for pico_ipv6_nd: queue for pending frames"); - - - tcase_add_test(TCase_pico_nd_new_expire_time, tc_pico_nd_new_expire_time); - suite_add_tcase(s, TCase_pico_nd_new_expire_time); - tcase_add_test(TCase_pico_nd_discover, tc_pico_nd_discover); - suite_add_tcase(s, TCase_pico_nd_discover); - tcase_add_test(TCase_neigh_options, tc_neigh_options); - suite_add_tcase(s, TCase_neigh_options); - tcase_add_test(TCase_neigh_adv_complete, tc_neigh_adv_complete); - suite_add_tcase(s, TCase_neigh_adv_complete); - tcase_add_test(TCase_neigh_adv_reconfirm_router_option, tc_neigh_adv_reconfirm_router_option); - suite_add_tcase(s, TCase_neigh_adv_reconfirm_router_option); - tcase_add_test(TCase_neigh_adv_reconfirm, tc_neigh_adv_reconfirm); - suite_add_tcase(s, TCase_neigh_adv_reconfirm); - tcase_add_test(TCase_neigh_adv_check_solicited, tc_neigh_adv_check_solicited); - suite_add_tcase(s, TCase_neigh_adv_check_solicited); - tcase_add_test(TCase_neigh_adv_process, tc_neigh_adv_process); - suite_add_tcase(s, TCase_neigh_adv_process); - tcase_add_test(TCase_pico_ipv6_neighbor, tc_pico_ipv6_neighbor); - suite_add_tcase(s, TCase_pico_ipv6_neighbor); - tcase_add_test(TCase_neighbor_from_sol, tc_neighbor_from_sol); - suite_add_tcase(s, TCase_neighbor_from_sol); - tcase_add_test(TCase_neigh_sol_process, tc_neigh_sol_process); - suite_add_tcase(s, TCase_neigh_sol_process); - tcase_add_test(TCase_icmp6_initial_checks, tc_icmp6_initial_checks); - suite_add_tcase(s, TCase_icmp6_initial_checks); - tcase_add_test(TCase_neigh_adv_mcast_validity_checks, tc_neigh_adv_mcast_validity_checks); - suite_add_tcase(s, TCase_neigh_adv_mcast_validity_checks); - tcase_add_test(TCase_neigh_sol_mcast_validity_checks, tc_neigh_sol_mcast_validity_checks); - suite_add_tcase(s, TCase_neigh_sol_mcast_validity_checks); - tcase_add_test(TCase_neigh_adv_validity_checks, tc_neigh_adv_validity_checks); - suite_add_tcase(s, TCase_neigh_adv_validity_checks); - tcase_add_test(TCase_neigh_sol_validity_checks, tc_neigh_sol_validity_checks); - suite_add_tcase(s, TCase_neigh_sol_validity_checks); - tcase_add_test(TCase_neigh_adv_checks, tc_neigh_adv_checks); - suite_add_tcase(s, TCase_neigh_adv_checks); - tcase_add_test(TCase_pico_nd_router_sol_recv, tc_pico_nd_router_sol_recv); - suite_add_tcase(s, TCase_pico_nd_router_sol_recv); - tcase_add_test(TCase_pico_nd_router_adv_recv, tc_pico_nd_router_adv_recv); - suite_add_tcase(s, TCase_pico_nd_router_adv_recv); - tcase_add_test(TCase_pico_nd_neigh_sol_recv, tc_pico_nd_neigh_sol_recv); - suite_add_tcase(s, TCase_pico_nd_neigh_sol_recv); - tcase_add_test(TCase_pico_nd_neigh_adv_recv, tc_pico_nd_neigh_adv_recv); - suite_add_tcase(s, TCase_pico_nd_neigh_adv_recv); - tcase_add_test(TCase_pico_nd_redirect_recv, tc_pico_nd_redirect_recv); - suite_add_tcase(s, TCase_pico_nd_redirect_recv); - tcase_add_test(TCase_pico_ipv6_nd_timer_callback, tc_pico_ipv6_nd_timer_callback); - suite_add_tcase(s, TCase_pico_ipv6_nd_timer_callback); - tcase_add_test(TCase_pico_nd_queue, tc_pico_nd_queue); - suite_add_tcase(s, TCase_pico_nd_queue); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} -#else -int main(void) -{ - return 0; -} - -#endif diff --git a/ext/picotcp/test/unit/modunit_pico_mdns.c b/ext/picotcp/test/unit/modunit_pico_mdns.c deleted file mode 100644 index 45688b2..0000000 --- a/ext/picotcp/test/unit/modunit_pico_mdns.c +++ /dev/null @@ -1,2227 +0,0 @@ -#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_mdns.h" -#include "pico_tree.h" -#include "pico_dev_mock.c" -#include "modules/pico_mdns.c" -#include "check.h" - -Suite *pico_suite(void); -void add_records(void); /* MARK: helper to add records to MyRecords s*/ -int mdns_init(void); /* MARK: Initialise mDNS module */ - -static int amount_callback_executed = 0; -void callback( pico_mdns_rtree *tree, char *str, void *arg); -void callback( pico_mdns_rtree *tree, - char *str, - void *arg ) /* MARK: Generic callback */ -{ - IGNORE_PARAMETER(tree); - IGNORE_PARAMETER(str); - IGNORE_PARAMETER(arg); - /* Do nothing, because fail_unless and fail_if don't work here */ - amount_callback_executed++; -} - -int mdns_init() /* MARK: Initialise mDNS module */ -{ - struct mock_device *mock = NULL; - - struct pico_ip4 local = { - .addr = long_be(0x0a280064) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - - mock = pico_mock_create(NULL); - if (!mock) { - return -1; - } - - pico_ipv4_link_add(mock->dev, local, netmask); - - /* Try to initialise the mDNS module right */ - return pico_mdns_init("host.local", local, callback, NULL); -} - -#define PICO_MDNS_COOKIE_DECLARE(name) \ - struct pico_mdns_cookie (name) = \ - { \ - {&LEAF, pico_dns_question_cmp}, \ - {&LEAF, pico_mdns_record_cmp}, \ - {&LEAF, pico_mdns_record_cmp}, \ - 0, 0, 0, 0, 0, NULL, NULL \ - } - -START_TEST(tc_mdns_init) /* MARK: mdns_init */ -{ - int ret = 0; - struct pico_ip4 local = { - 0 - }; - char hostname[] = "host.local"; - - printf("*********************** starting %s * \n", __func__); - - pico_stack_init(); - - /* Try to initialise the mDNS module wrong */ - ret = pico_mdns_init(NULL, local, callback, NULL); - fail_unless(ret, "mdns_init failed checking params!\n"); - - /* Try to initialise the mDNS module wrong */ - ret = pico_mdns_init(hostname, local, callback, NULL); - fail_unless(ret, "mdns_init failed checking params!\n"); - - /* Try to initialise the mDNS module wrong */ - ret = pico_mdns_init(hostname, local, NULL, NULL); - fail_unless(ret, "mdns_init failed checking params!\n"); - - ret = mdns_init(); - fail_unless(0 == ret, "mdns_init failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_cmp_name_type) /* MARK: mdns_record_cmp_name_type*/ -{ - struct pico_mdns_record a = { - 0 - }; - struct pico_mdns_record b = { - 0 - }; - char url1[] = "foo.local"; - char url3[] = "a.local"; - struct pico_ip4 rdata = { - 0 - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create different test records */ - a.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!a.record, "Record A could not be created!\n"); - b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b.record, "Record B could not be created!\n"); - - /* Try to compare records with equal rname but different type */ - ret = pico_mdns_record_cmp_name_type((void *) &a, (void *) &b); - fail_unless(ret > 0, "mdns_record_cmp_name_type failed with different types!\n"); - pico_dns_record_delete((void**)(void **)&(a.record)); - pico_dns_record_delete((void**)(void **)&(b.record)); - - /* Create different test records */ - a.record = pico_dns_record_create(url3, (uint8_t *)url1, (uint16_t) strlen(url1), &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a.record, "Record A could not be created!\n"); - b.record = pico_dns_record_create(url3, (uint8_t *)url1, (uint16_t) strlen(url1), &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b.record, "Record B could not be created!\n"); - - /* Try to compare records with different rname but equal type */ - ret = pico_mdns_record_cmp_name_type((void *) &a, (void *) &b); - fail_unless(!ret, "mdns_record_cmp_name_type failed!\n"); - pico_dns_record_delete((void**)(void **)&(a.record)); - pico_dns_record_delete((void**)(void **)&(b.record)); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_cmp) /* MARK: mdns_record_cmp */ -{ - struct pico_mdns_record a = { - 0 - }; - struct pico_mdns_record b = { - 0 - }; - char url1[] = "foo.local"; - char url3[] = "a.local"; - struct pico_ip4 rdata = { - 0 - }; - uint16_t len = 0; - int ret = 0; - struct pico_ip4 firstIP = { - .addr = 0x7778797A - }; - struct pico_ip4 secondIP = { - .addr = 0x5758595A - }; - - printf("*********************** starting %s * \n", __func__); - - /* Create test records */ - a.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!(a.record), "Record A could not be created!\n"); - b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!(b.record), "Record B could not be created!\n"); - - /* Try to compare equal records */ - ret = pico_mdns_record_cmp((void *) &a, (void *) &b); - fail_unless(!ret, "mdns_record_cmp failed with equal records!\n"); - pico_dns_record_delete((void**)(void **)&(a.record)); - pico_dns_record_delete((void**)(void **)&(b.record)); - - /* Create different test records */ - a.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!a.record, "Record A could not be created!\n"); - b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b.record, "Record B could not be created!\n"); - - /* Try to compare records with equal rname but different type */ - ret = pico_mdns_record_cmp((void *) &a, (void *) &b); - fail_unless(ret > 0, "mdns_record_cmp failed with same name, different types!\n"); - pico_dns_record_delete((void**)(void **)&(a.record)); - pico_dns_record_delete((void**)(void **)&(b.record)); - - /* Create different test records */ - a.record = pico_dns_record_create(url3, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a.record, "Record A could not be created!\n"); - b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!b.record, "Record B could not be created!\n"); - - /* Try to compare records with different rname but equal type */ - ret = pico_mdns_record_cmp((void *) &a, (void *) &b); - fail_unless(ret < 0, "mdns_record_cmp failed with different name, same types!\n"); - pico_dns_record_delete((void**)(void **)&(a.record)); - pico_dns_record_delete((void**)(void **)&(b.record)); - - - /* Create different test records */ - a.record = pico_dns_record_create(url1, &firstIP, 4, &len, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!a.record, "Record A could not be created!\n"); - b.record = pico_dns_record_create(url1, &secondIP, 4, &len, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN, 0); - fail_if(!b.record, "Record B could not be created!\n"); - - /* Try to compare records with equal rname but equal type different IP address (testing the effect of pico_tolower) */ - ret = pico_mdns_record_cmp((void *) &a, (void *) &b); - fail_unless(ret > 0, "mdns_record_cmp failed with same name, same types, tolower separated different rdata!\n"); - pico_dns_record_delete((void**)(void **)&(a.record)); - pico_dns_record_delete((void**)(void **)&(b.record)); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_cookie_cmp) /* MARK: mdns_cookie_cmp */ -{ - PICO_MDNS_COOKIE_DECLARE(a); - PICO_MDNS_COOKIE_DECLARE(b); - struct pico_dns_question *question1 = NULL; - struct pico_dns_question *question2 = NULL; - struct pico_dns_question *question3 = NULL; - struct pico_dns_question *question4 = NULL; - struct pico_dns_question *question5 = NULL; - struct pico_mdns_record record1 = { - 0 - }, record2 = { - 0 - }, record3 = { - 0 - }, - record4 = { - 0 - }; - char url1[] = "foo.local"; - char url2[] = "bar.local"; - char url3[] = "pi.local"; - char url4[] = "ab.local"; - struct pico_ip4 rdata = { - 0 - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create some questions */ - question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question1, "Could not create question 1!\n"); - question2 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_PTR, - PICO_DNS_CLASS_IN, 0); - fail_if(!question2, "Could not create question 2!\n"); - question3 = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question3, "Could not create question 3!\n"); - question4 = pico_dns_question_create(url4, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!question4, "Could not create question 4!\n"); - question5 = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_TYPE_AAAA, 0); - fail_if(!question5, "Could not create question 5!\n"); - - /* Create test records */ - record1.record = pico_dns_record_create(url1, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record1.record, "Record 1 could not be created!\n"); - record2.record = pico_dns_record_create(url1, &rdata, 4, &len, - PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!record2.record, "Record 2 could not be created!\n"); - record3.record = pico_dns_record_create(url2, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record3.record, "Record 3 could not be created!\n"); - record4.record = pico_dns_record_create(url4, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record4.record, "Record 3 could not be created!\n"); - - /* Create 2 exactly the same cookies */ - pico_tree_insert(&(a.qtree), question1); - pico_tree_insert(&(a.qtree), question2); - pico_tree_insert(&(a.qtree), question3); - pico_tree_insert(&(a.qtree), question4); - pico_tree_insert(&(a.qtree), question5); - pico_tree_insert(&(a.antree), &record1); - pico_tree_insert(&(a.antree), &record2); - pico_tree_insert(&(a.antree), &record3); - pico_tree_insert(&(a.antree), &record4); - - pico_tree_insert(&(b.qtree), question1); - pico_tree_insert(&(b.qtree), question2); - pico_tree_insert(&(b.qtree), question3); - pico_tree_insert(&(b.qtree), question4); - pico_tree_insert(&(b.qtree), question5); - pico_tree_insert(&(b.antree), &record1); - pico_tree_insert(&(b.antree), &record2); - pico_tree_insert(&(b.antree), &record3); - pico_tree_insert(&(b.antree), &record4); - - /* Try to compare exactly the same cookies*/ - ret = pico_mdns_cookie_cmp((void *) &a, (void *) &b); - fail_unless(0 == ret, "mdns_cookie_cmp failed with equal cookies!\n"); - - /* Try to compare cookies but B a larger question than A*/ - pico_tree_delete(&(a.qtree), question2); - ret = pico_mdns_cookie_cmp((void *) &a, (void *) &b); - fail_unless(ret > 0, "mdns_cookie_cmp failed with larger question A!\n"); - - /* Insert more possibilities here.. */ - - PICO_DNS_QTREE_DESTROY(&(b.qtree)); - pico_dns_record_delete((void **)&(record1.record)); - pico_dns_record_delete((void **)&(record2.record)); - pico_dns_record_delete((void **)&(record3.record)); - pico_dns_record_delete((void **)&(record4.record)); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_suffix_to_uint16) /* MARK: mdns_suffix_to_uint16 */ -{ - char url[10] = "-2"; - char url2[10] = "-10"; - char url3[10] = "-500000"; - char *o = NULL, *c = NULL; - - printf("*********************** starting %s * \n", __func__); - - o = url; - c = url + 2; - fail_unless(2 == pico_mdns_suffix_to_uint16(o, c), - "mdns_suffix_to_uint16 failed with correct suffix 2!\n"); - - o = url2; - c = url2 + 3; - fail_unless(10 == pico_mdns_suffix_to_uint16(o, c), - "mdns_suffix_to_uint16 failed with correct suffix 10!\n"); - - o = url3; - c = url3 + 7; - fail_unless(0 == pico_mdns_suffix_to_uint16(o, c), - "mdns_suffix_to_uint16 failed with wrong suffix 500000\n"); - - fail_unless(0 == pico_mdns_suffix_to_uint16(NULL, NULL), - "mdns_suffix_to_uint16 failed with NULL-pointers given\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_cookie_delete) /* MARK: mdns_cookie_delete */ -{ - struct pico_mdns_cookie *a = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - - printf("*********************** starting %s * \n", __func__); - - fail_unless(pico_mdns_cookie_delete((void **)&a), - "mdns_cookie_delete failed checking params!\n"); - a = pico_mdns_cookie_create(qtree, antree, artree, 0, 0, NULL, NULL); - fail_unless(!pico_mdns_cookie_delete((void **)&a), - "mdns_cookie_delete failed!\n"); - - fail_unless(pico_mdns_cookie_delete(NULL), - "mdns_cookie_delete failed checking NULL-pointer"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_cookie_create) /* MARK: mdns_cookie_create */ -{ - struct pico_mdns_cookie *a = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - - printf("*********************** starting %s * \n", __func__); - - a = pico_mdns_cookie_create(qtree, antree, artree, 0, 0, NULL, NULL); - fail_if(!a, "mdns_cookie_create failed!\n"); - - pico_mdns_cookie_delete((void **)&a); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_cookie_tree_find_query_cookie) /* MARK: mdns_ctree_find_cookie */ -{ - struct pico_mdns_cookie *a = NULL, *b = NULL; - PICO_DNS_QTREE_DECLARE(qtree_a); - PICO_DNS_QTREE_DECLARE(qtree_b); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - struct pico_dns_question *question1 = NULL; - struct pico_dns_question *question2 = NULL; - struct pico_dns_question *question3 = NULL; - struct pico_dns_question *question4 = NULL; - struct pico_dns_question *question5 = NULL; - char url1[] = "foo.local"; - char url2[] = "bar.local"; - char url3[] = "pi.local"; - char url4[] = "ab.local"; - char url5[] = "t.local"; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create some questions */ - question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question1, "Could not create question 1!\n"); - question2 = pico_dns_question_create(url5, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_PTR, - PICO_DNS_CLASS_IN, 0); - fail_if(!question2, "Could not create question 2!\n"); - question3 = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question3, "Could not create question 3!\n"); - question4 = pico_dns_question_create(url4, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_AAAA, - PICO_DNS_CLASS_IN, 0); - fail_if(!question4, "Could not create question 4!\n"); - question5 = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question5, "Could not create question 5!\n"); - - pico_tree_insert(&qtree_a, question3); - pico_tree_insert(&qtree_a, question4); - - pico_tree_insert(&qtree_b, question1); - pico_tree_insert(&qtree_b, question2); - pico_tree_insert(&qtree_b, question5); - - a = pico_mdns_cookie_create(qtree_a, antree, artree, 1, - PICO_MDNS_PACKET_TYPE_QUERY, NULL, NULL); - fail_if(!a, "mdns_cookie_create failed!\n"); - b = pico_mdns_cookie_create(qtree_b, antree, artree, 1, - PICO_MDNS_PACKET_TYPE_QUERY, NULL, NULL); - fail_if(!b, "mdns_cookie_create failed!\n"); - - pico_tree_insert(&Cookies, a); - pico_tree_insert(&Cookies, b); - - fail_unless(b == pico_mdns_ctree_find_cookie("\3foo\5local", PICO_MDNS_PACKET_TYPE_QUERY), - "mdns_cookie_tree_find_query_cookie failed with foo.local\n"); - - fail_unless(a == pico_mdns_ctree_find_cookie("\2pi\5local", PICO_MDNS_PACKET_TYPE_QUERY), - "mdns_cookie_tree_find_query_cookie failed with pi.local\n"); - - fail_unless(NULL == pico_mdns_ctree_find_cookie("bla.local", PICO_MDNS_PACKET_TYPE_QUERY), - "mdns_cookie_tree_find_query_cookie failed with foo.local\n"); - - pico_tree_delete(&Cookies, a); - pico_tree_delete(&Cookies, b); - pico_mdns_cookie_delete((void **)&a); - pico_mdns_cookie_delete((void **)&b); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_cookie_apply_spt) /* MARK: mdns_cookie_apply_spt */ -{ - PICO_MDNS_COOKIE_DECLARE(a); - struct pico_mdns_record record1 = { - 0 - }, record2 = { - 0 - }, record3 = { - 0 - }, - record4 = { - 0 - }; - char url1[] = "foo.local"; - char url2[] = "bar.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata2 = { - long_be(0xFFFFFFFF) - }; - int ret = 0; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create test records */ - record1.record = pico_dns_record_create(url1, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record1.record, "Record 1 could not be created!\n"); - record2.record = pico_dns_record_create(url2, &rdata2, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record2.record, "Record 2 could not be created!\n"); - record3.record = pico_dns_record_create(url1, &rdata2, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record3.record, "Record 3 could not be created!\n"); - record4.record = pico_dns_record_create(url2, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record4.record, "Record 4 could not be created!\n"); - - /* Make it a probe cookie otherwise it will just return -1 */ - a.type = PICO_MDNS_PACKET_TYPE_PROBE; - - /* Need to initialise the stack to allow timer scheduling IMPORTANT! */ - pico_stack_init(); - - /* Create 2 exactly the same cookies */ - pico_tree_insert(&(a.antree), &record1); - pico_tree_insert(&(a.antree), &record2); - pico_tree_insert(&MyRecords, &record1); - pico_tree_insert(&MyRecords, &record2); - - ret = pico_mdns_cookie_apply_spt(&a, record3.record); - fail_unless(ret, "mdns_cookie_apply_spt failed checking parms!\n"); - - PICO_MDNS_SET_FLAG(record1.flags, PICO_MDNS_RECORD_CURRENTLY_PROBING); - PICO_MDNS_SET_FLAG(record2.flags, PICO_MDNS_RECORD_CURRENTLY_PROBING); - - /* Check with peer record which is lexicographically later */ - ret = pico_mdns_cookie_apply_spt(&a, record3.record); - fail_unless(0 == ret, "mdns_cookie_apply_spt failed!\n"); - - /* Check with peer record which is lexicographically earlier */ - ret = pico_mdns_cookie_apply_spt(&a, record4.record); - fail_unless(0 == ret, "mdns_cookie_apply_spt failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_is_suffix_present) /* MARK: mdns_is_suffix_present */ -{ - char name1[16] = { - 5, 'v', 'l', 'e', 'e', 's', 5, 'l', 'o', 'c', 'a', 'l', 0 - }; - char name2[17] = { - 8, 'v', 'l', 'e', 'e', 's', ' ', '-', '2', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name6[20] = { - 10, 'v', 'l', 'e', 'e', 's', ' ', '-', 'a', '-', '2', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name7[18] = { - 9, 'v', 'l', 'e', 'e', 's', ' ', '-', '9', 'a', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name9[17] = { - 7, 'v', 'l', 'e', 'e', 's', ' ', '-', '0', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char *o_index = NULL; - char *c_index = NULL; - uint16_t present = 0; - - printf("*********************** starting %s * \n", __func__); - present = pico_mdns_is_suffix_present(name1, &o_index, &c_index); - fail_unless(!present, - "There is no suffix present!\n"); - fail_unless(NULL == o_index && NULL == c_index, - "There should be no indexes!\n"); - - present = pico_mdns_is_suffix_present(name2, &o_index, &c_index); - fail_unless(present, - "is_suffix_present failed with suffix!\n"); - fail_unless((name2 + 7) == o_index && (name2 + 9) == c_index, - "is_suffix_pressent failed!\n"); - fail_unless(present == 2, "Suffix should be 2!\n"); - - present = pico_mdns_is_suffix_present(name7, &o_index, &c_index); - fail_unless(!present, - "There is no suffix present!\n"); - fail_unless(NULL == o_index && NULL == c_index, - "There should be no indexes!\n"); - - present = pico_mdns_is_suffix_present(name6, &o_index, &c_index); - fail_unless(present, - "is_suffix_present failed with suffix!\n"); - fail_unless((name6 + 9) == o_index && (name6 + 11) == c_index, - "is_suffix_present failed!\n"); - fail_unless(present == 2, "Suffix should be 2!\n"); - - present = pico_mdns_is_suffix_present(name9, &o_index, &c_index); - fail_unless(!present, - "is_suffix_present failed with suffix 0!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -#pragma GCC diagnostic push /* require GCC 4.6 */ -#pragma GCC diagnostic ignored "-Woverflow" -START_TEST(tc_pico_itoa) /* MARK: itoa */ -{ - char num[10] = { - 0 - }; - - uint16_t t1 = 10; - printf("*********************** starting %s * \n", __func__); - - pico_itoa(t1, num); - fail_unless(0 == strcmp(num, "10"), "ITOA with %d failed: %s\n", t1, num); - memcpy(num, "\0\0\0\0\0\0\0\0\0\0", 10); - pico_itoa(65535, num); - fail_unless(0 == strcmp(num, "65535"), "ITOA with %d failed: %s\n", 65535, num); - memcpy(num, "\0\0\0\0\0\0\0\0\0\0", 10); - pico_itoa(0, num); - fail_unless(0 == strcmp(num, "0"), "ITOA with %d failed: %s\n", 0, num); - memcpy(num, "\0\0\0\0\0\0\0\0\0\0", 10); - pico_itoa(65536, num); - fail_unless(0 == strcmp(num, "0"), "ITOA with %d failed: %s\n", 65536, num); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -#pragma GCC diagnostic pop /* require GCC 4.6 */ -START_TEST(tc_mdns_resolve_name_conflict) /* MARK: mdns_resolve_name_conflict */ -{ - char name1[13] = { - 5, 'v', 'l', 'e', 'e', 's', 5, 'l', 'o', 'c', 'a', 'l', 0 - }; - char name2[17] = { - 7, 'v', 'l', 'e', 'e', 's', '-', '2', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name3[18] = { - 8, 'v', 'l', 'e', 'e', 's', '-', '1', '0', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name4[17] = { - 7, 'v', 'l', 'e', 'e', 's', '-', '9', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name5[16] = { - 6, 'v', 'l', 'e', 'e', 's', '-', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name6[17] = { - 7, 'v', 'l', 'e', 'e', 's', '-', 'a', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char name7[18] = { - 8, 'v', 'l', 'e', 'e', 's', '-', '9', 'a', 5, 'l', 'o', 'c', 'a', 'l', '\0' - }; - char *ret = NULL; - - printf("*********************** starting %s * \n", __func__); - - ret = pico_mdns_resolve_name_conflict(name1); - fail_unless(0 == strcmp(ret, "\x7vlees-2\5local"), - "mdns_conflict_resolve_name failed 'vlees.local' to %s!\n", - ret); - PICO_FREE(ret); - ret = pico_mdns_resolve_name_conflict(name2); - fail_unless(0 == strcmp(ret, "\x7vlees-3\5local"), - "mdns_conflict_resolve_name failed 'vlees-2.local' to %s!\n", - ret); - PICO_FREE(ret); - ret = pico_mdns_resolve_name_conflict(name3); - fail_unless(0 == strcmp(ret, "\x8vlees-11\5local"), - "mdns_conflict_resolve_name failed 'vlees-10.local' to %s!\n", - ret); - PICO_FREE(ret); - ret = pico_mdns_resolve_name_conflict(name4); - fail_unless(0 == strcmp(ret, "\x8vlees-10\5local"), - "mdns_conflict_resolve_name failed 'vlees-9.local' to %s!\n", - ret); - PICO_FREE(ret); - ret = pico_mdns_resolve_name_conflict(name5); - fail_unless(0 == strcmp(ret, "\x8vlees--2\5local"), - "mdns_conflict_resolve_name failed 'vlees--2.local' to %s!\n", - ret); - PICO_FREE(ret); - ret = pico_mdns_resolve_name_conflict(name6); - fail_unless(0 == strcmp(ret, "\x9vlees-a-2\5local"), - "mdns_conflict_resolve_name failed 'vlees-a-2.local' to %s!\n", - ret); - PICO_FREE(ret); - ret = pico_mdns_resolve_name_conflict(name7); - fail_unless(0 == strcmp(ret, "\xavlees-9a-2\5local"), - "mdns_conflict_resolve_name failed 'vlees-9a-2.local' to %s!\n", - ret); - PICO_FREE(ret); - - fail_unless(NULL == pico_mdns_resolve_name_conflict(NULL), - "mdns_conflict_resolvE_name failed checking params!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_generate_new_records) /* MARK: mdns_generate_new_records */ -{ - PICO_MDNS_RTREE_DECLARE(ctree); - PICO_MDNS_RTREE_DECLARE(ntree); - struct pico_mdns_record *record = NULL; - char url[] = "foo.local"; - char url2[] = "\3foo\5local"; - char url3[] = "\7foo (2)\5local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - - printf("*********************** starting %s * \n", __func__); - - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - pico_tree_insert(&ctree, record); - - ntree = pico_mdns_generate_new_records(&ctree, url2, - url3); - - fail_unless(1 == pico_tree_count(&ntree), "new_tree has wrong count!\n"); - record = pico_tree_firstNode(ntree.root)->keyValue; - fail_unless(strcmp(record->record->rname, url3) == 0, - "New name isn't correctly copied %s!\n", record->record->rname); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_cookie_resolve_conflict) /* MARK: mdns_cookie_resolve_conflict */ -{ - struct pico_mdns_cookie *a = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - struct pico_dns_question *question = NULL; - struct pico_mdns_record *record = NULL; - char url[] = "foo.local"; - char url2[] = "\3foo\5local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - int ret = 0; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - question = pico_dns_question_create(url, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question, "Question could not be created!\n"); - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - - /* Create 2 exactly the same cookies */ - pico_tree_insert(&antree, record); - pico_tree_insert(&qtree, question); - - /* Make it a probe cookie otherwise it will just return -1 */ - a = pico_mdns_cookie_create(qtree, antree, artree, 1, - PICO_MDNS_PACKET_TYPE_PROBE, - callback, NULL); - - /* Need to initialise the stack to allow timer scheduling IMPORTANT! */ - pico_stack_init(); - ret = mdns_init(); - fail_unless(0 == ret, "mdns_init failed!\n"); - - /* Cookie needs to be removed from cookie tree so we need to add it first */ - pico_tree_insert(&Cookies, a); - - ret = pico_mdns_cookie_resolve_conflict(a, url2); - fail_unless(0 == ret, "mdns_cookie_resolve_conflict failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_question_create) /* MARK: mdns_question_create */ -{ - struct pico_dns_question *question = NULL; - char url[] = "1.2.3.4"; - char cmpbuf[22] = { - 0x01u, '4', - 0x01u, '3', - 0x01u, '2', - 0x01u, '1', - 0x07u, 'i', 'n', '-', 'a', 'd', 'd', 'r', - 0x04u, 'a', 'r', 'p', 'a', - 0x00u - }; - uint16_t len = 0; - - printf("*********************** starting %s * \n", __func__); - - question = pico_mdns_question_create("foo.local", - &len, - PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_MDNS_QUESTION_FLAG_UNICAST_RES, - 0); - fail_if(!question, "mdns_question_create returned NULL!\n"); - fail_unless(0 == strcmp(question->qname, "\3foo\5local"), - "mdns_question_create failed!\n"); - fail_unless(0x8001 == short_be(question->qsuffix->qclass), - "mdns_quesiton_create failed setting QU bit!\n"); - pico_dns_question_delete((void**)&question); - - question = pico_mdns_question_create("foo.local", - &len, - PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_MDNS_QUESTION_FLAG_PROBE, - 0); - fail_if(!question, "mdns_question_create returned NULL!\n"); - fail_unless(0 == strcmp(question->qname, "\3foo\5local"), - "mdns_question_create failed!\n"); - fail_unless(PICO_DNS_TYPE_ANY == short_be(question->qsuffix->qtype), - "mdns_quesiton_create failed setting type to ANY!\n"); - pico_dns_question_delete((void**)&question); - - question = pico_mdns_question_create(url, - &len, - PICO_PROTO_IPV4, - PICO_DNS_TYPE_PTR, - 0, 1); - fail_if(!question, "mdns_question_create returned NULL!\n"); - fail_unless(0 == strcmp(question->qname, cmpbuf), - "mdns_question_create failed!\n"); - pico_dns_question_delete((void**)&question); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_resolve_conflict) /* MARK: mdns_record_resolve_conflict */ -{ - struct pico_mdns_record *record = NULL; - char url[] = "foo.local"; - char url2[] = "\3foo\5local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - /* Need to initialise the stack to allow timer scheduling IMPORTANT! */ - pico_stack_init(); - - ret = mdns_init(); - fail_unless(0 == ret, "mdns_init failed!\n"); - - ret = pico_mdns_record_resolve_conflict(record, url2); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_am_i_lexi_later) /* MARK: mdns_record_am_i_lexi_later */ -{ - struct pico_mdns_record record1 = { - 0 - }, record2 = { - 0 - }, record3 = { - 0 - }, - record4 = { - 0 - }; - char url1[] = "foo.local"; - char url2[] = "bar.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata2 = { - long_be(0xFFFFFFFF) - }; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create test records */ - record1.record = pico_dns_record_create(url1, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record1.record, "Record 1 could not be created!\n"); - record2.record = pico_dns_record_create(url2, &rdata2, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record2.record, "Record 2 could not be created!\n"); - record3.record = pico_dns_record_create(url1, &rdata2, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record3.record, "Record 3 could not be created!\n"); - record4.record = pico_dns_record_create(url2, &rdata, 4, &len, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!record4.record, "Record 4 could not be created!\n"); - - ret = pico_mdns_record_am_i_lexi_later(&record1, &record3); - fail_unless(ret < 0, "mdns_record_am_i_lexi_later failed!\n"); - - ret = pico_mdns_record_am_i_lexi_later(&record2, &record4); - fail_unless(ret > 0, "mdns_record_am_i_lexi_later failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_copy_with_new_name) /* MARK: copy_with_new_name */ -{ - struct pico_mdns_record *record = NULL, *copy = NULL; - char url[] = "foo.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - - printf("*********************** starting %s * \n", __func__); - /* Create a record */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - - /* Try to create a copy with a new name */ - copy = pico_mdns_record_copy_with_new_name(record, "\4test\5local"); - fail_if(!copy, "mdns_record_copy_with_new_name returned NULL!\n"); - fail_unless(0 == strcmp(copy->record->rname, "\4test\5local"), - "mdns_record_copy_with_new_name didn't copy name right!\n"); - fail_unless(strlen("\4test\5local") + 1 == copy->record->rname_length, - "mdns_record_copy_with_new_name didn't update namelength!\n"); - - pico_mdns_record_delete((void **)&record); - pico_mdns_record_delete((void **)©); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_copy) /* MARK: mdns_record_copy */ -{ - struct pico_mdns_record *record = NULL, *copy = NULL; - char url[] = "foo.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - - printf("*********************** starting %s * \n", __func__); - /* Create a record */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - - /* Try to copy */ - copy = pico_mdns_record_copy(record); - fail_if(!copy, "mdns_record_copy returned NULL!\n"); - fail_if(record == copy, "Pointers point to same struct!\n"); - fail_unless(0 == strcmp(copy->record->rname, record->record->rname), - "mdns_record_copy didn't copy names right!\n"); - fail_unless(copy->claim_id == record->claim_id, - "mdns_record_copy didn't copy claim_id right!\n"); - fail_unless(copy->current_ttl == record->current_ttl, - "mdns_record_copy didn't copy current_ttl right!\n"); - fail_unless(copy->flags == record->flags, - "mdns_record_copy didn't copy flags right!\n"); - - pico_mdns_record_delete((void **)&record); - pico_mdns_record_delete((void **)©); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_create) /* MARK: mdns_record_create */ -{ - struct pico_mdns_record *record = NULL; - char url[] = "foo.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - printf("*********************** starting %s * \n", __func__); - /* Create a record */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - fail_unless(0 == strcmp(record->record->rname, "\3foo\5local"), - "mdns_record_create didn't convert rname properly!\n"); - fail_unless(0x8001 == short_be(record->record->rsuffix->rclass), - "mdns_record_create didn't set QU flag correctly!\n"); - pico_mdns_record_delete((void **)&record); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_delete) /* MARK: mdns_record_delete */ -{ - struct pico_mdns_record *record = NULL; - char url[] = "foo.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - /* Create a record */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!(record->record), "Record could not be created!\n"); - - /* Try to delete the record */ - ret = pico_mdns_record_delete((void **)&record); - fail_unless(0 == ret, "mdns_record_delete returned error!\n"); - fail_unless(!record, "mdns_record_delete didn't delete properly"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -void add_records( void ) /* MARK: helper to add records to MyRecords s*/ -{ - struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, - *record3 = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata1 = { - long_be(0xFFFFFFFF) - }; - char url[] = "foo.local"; - char url1[] = "bar.local"; - - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - (PICO_MDNS_RECORD_UNIQUE | - PICO_MDNS_RECORD_PROBED | - PICO_MDNS_RECORD_HOSTNAME)); - fail_if(!record, "Record could not be created!\n"); - printf("Is hostname record: %d\n", IS_HOSTNAME_RECORD(record)); - - /* Create 2 PTR records to URL */ - record1 = pico_mdns_record_create(url, url, (uint16_t) strlen(url), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record1, "Record could not be created!\n"); - - /* Simulate that this record is probed */ - record1->flags |= PICO_MDNS_RECORD_PROBED; - - record2 = pico_mdns_record_create(url, url1, (uint16_t) strlen(url1), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Create a totally different record */ - record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Add the records to the tree */ - pico_tree_insert(&MyRecords, record); - pico_tree_insert(&MyRecords, record1); - pico_tree_insert(&MyRecords, record2); - pico_tree_insert(&MyRecords, record3); -} -START_TEST(tc_mdns_record_tree_find_name) /* MARK: mdns_record_find_name */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - int found = 1; - - printf("*********************** starting %s * \n", __func__); - - add_records(); - - hits = pico_mdns_rtree_find_name(&MyRecords, "\3foo\5local", 0); - fail_unless(2 == pico_tree_count(&hits), - "mdns_record_tree_find_name should find 2 records here!\n"); - pico_tree_foreach(node, &hits) { - if ((record = node->keyValue)) { - if (strcmp(record->record->rname, "\3foo\5local")) - found = 0; - } - } - fail_unless(1 == found, - "mdns_record_tree_find_name returned records with other name!\n"); - - hits = pico_mdns_rtree_find_name(&MyRecords, "\3bar\5local", 0); - fail_unless(1 == pico_tree_count(&hits), - "mdns_record_tree_find_name should find 1 record here!\n"); - record = pico_tree_firstNode(hits.root)->keyValue; - fail_unless(0 == strcmp(record->record->rname, - "\3bar\5local"), - "mdns_record_tree_find_name returned record with other name!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_tree_find_name_type) /* MARK: mdns_record_find_name_type */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - struct pico_tree_node *node = NULL; - struct pico_mdns_record *record = NULL; - int found = 1; - char url[] = "\3foo\5local"; - char url2[] = "\3bar\5local"; - printf("*********************** starting %s * \n", __func__); - - add_records(); - - /* Try to find the first A record */ - hits = pico_mdns_rtree_find_name_type(&MyRecords, url, PICO_DNS_TYPE_A, 0); - fail_unless(1 == pico_tree_count(&hits), - "mdns_record_tree_find_name should find 1 record here!\n"); - record = pico_tree_firstNode(hits.root)->keyValue; - fail_unless(0 == strcmp(record->record->rname, url), - "mdns_record_tree_find_name returned record with other name!\n"); - - /* Try to find the 2 PTR records */ - hits = pico_mdns_rtree_find_name_type(&MyRecords, url, PICO_DNS_TYPE_PTR, 0); - pico_tree_foreach(node, &hits) { - if ((record = node->keyValue)) { - if (strcmp(record->record->rname, url)) - found = 0; - } - } - fail_unless(1 == found, - "mdns_record_tree_find_name returned records with other name!\n"); - - /* Try to find the last A record */ - hits = pico_mdns_rtree_find_name_type(&MyRecords, url2, PICO_DNS_TYPE_A, 0); - fail_unless(1 == pico_tree_count(&hits), - "mdns_record_tree_find_name should find 1 record here!\n"); - record = pico_tree_firstNode(hits.root)->keyValue; - fail_unless(0 == strcmp(record->record->rname, url2), - "mdns_record_tree_find_name returned record with other name!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_tree_del_name) /* MARK: mdns_record_tree_del_name */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, - *record3 = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata1 = { - long_be(0xFFFFFFFF) - }; - char url[] = "foo.local"; - char url1[] = "bar.local"; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record, "Record could not be created!\n"); - - /* Create 2 PTR records to URL */ - record1 = pico_mdns_record_create(url, url, (uint16_t) strlen(url), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record1, "Record could not be created!\n"); - record2 = pico_mdns_record_create(url, url1, (uint16_t) strlen(url1), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Create a totally different record */ - record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Add the records to the tree */ - pico_tree_insert(&MyRecords, record); - pico_tree_insert(&MyRecords, record1); - pico_tree_insert(&MyRecords, record2); - pico_tree_insert(&MyRecords, record3); - - /* Try to del the first tree records */ - ret = pico_mdns_rtree_del_name(&MyRecords, "\3foo\5local"); - fail_unless(0 == ret, - "mdns_record_tree_del_name failed!\n"); - hits = pico_mdns_rtree_find_name(&MyRecords, "\3foo\5local", 0); - fail_unless(0 == pico_tree_count(&hits), - "mdns_record_tree_find_name should find 3 records here!\n"); - - hits = pico_mdns_rtree_find_name( &MyRecords, "\3bar\5local", 0); - fail_unless(1 == pico_tree_count(&hits), - "mdns_record_tree_find_name should find 1 record here!\n"); - record = pico_tree_first(&hits); - fail_unless(0 == strcmp(record->record->rname, "\3bar\5local"), - "mdns_record_tree_del_name failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_record_tree_del_name_type) /* MARK: mdns_record_tree_del_name_type */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - int ret = 0; - char url[] = "\3foo\5local"; - printf("*********************** starting %s * \n", __func__); - - add_records(); - - /* Try to del the two PTR records */ - ret = pico_mdns_rtree_del_name_type(&MyRecords, url, - PICO_DNS_TYPE_PTR); - fail_unless(0 == ret, "mdns_record_tree_del_name_type returned error!\n"); - - /* Try to find the 2 PTR records */ - hits = pico_mdns_rtree_find_name_type(&MyRecords, url, - PICO_DNS_TYPE_PTR, 0); - fail_unless(0 == pico_tree_count(&hits), - "mdns_record_tree_find_name_type returned PTR records!\n"); - - - /* Try to find the first A record */ - hits = pico_mdns_rtree_find_name_type(&MyRecords, url, - PICO_DNS_TYPE_A, 0); - fail_unless(1 == pico_tree_count(&hits), - "mdns_record_tree_del_name_type failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_my_records_add) /* MARK: mdns_my_records_add */ -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, - *record3 = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata1 = { - long_be(0xFFFFFFFF) - }; - char url[] = "foo.local"; - char url1[] = "bar.local"; - - printf("*********************** starting %s * \n", __func__); - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record, "Record could not be created!\n"); - - /* Create 2 PTR records to URL */ - record1 = pico_mdns_record_create(url, url, (uint16_t) strlen(url), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record1, "Record could not be created!\n"); - - /* Simulate that this record is not added again */ - record2 = pico_mdns_record_create(url, url1, (uint16_t) strlen(url1), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Create a totally different record */ - record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Add the records to the tree */ - pico_tree_insert(&rtree, record); - pico_tree_insert(&rtree, record1); - pico_tree_insert(&rtree, record2); - pico_tree_insert(&rtree, record3); - - pico_mdns_my_records_add(&rtree, 0); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_my_records_find_probed) /* MARK: mdns_my_records_find_probed */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - - printf("*********************** starting %s * \n", __func__); - - add_records(); - - hits = pico_mdns_my_records_find_probed(); - fail_unless(2 == pico_tree_count(&hits), - "mdns_my_records_find_probed failed %d!\n", - pico_tree_count(&hits)); - - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_my_records_find_to_probe) /* MARK: mdns_my_records_find_to_probe */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - - printf("*********************** starting %s * \n", __func__); - - add_records(); - - hits = pico_mdns_my_records_find_to_probe(); - fail_unless(1 == pico_tree_count(&hits), - "mdns_my_records_find_to_probe failed! %d\n", pico_tree_count(&hits)); - - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_my_records_claimed_id) /* MARK: mnds_my_records_claimed_id */ -{ - PICO_MDNS_RTREE_DECLARE(hits); - struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, - *record3 = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata1 = { - long_be(0xFFFFFFFF) - }; - char url[] = "foo.local"; - char url1[] = "bar.local"; - - printf("*********************** starting %s * \n", __func__); - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - record->claim_id = 1; - record->flags |= PICO_MDNS_RECORD_PROBED; - fail_if(!record, "Record could not be created!\n"); - - /* Create 2 PTR records to URL */ - record1 = pico_mdns_record_create(url, url, (uint16_t) strlen(url), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - record1->claim_id = 1; - record1->flags |= PICO_MDNS_RECORD_PROBED; - fail_if(!record1, "Record could not be created!\n"); - - /* Simulate that this record is not added again */ - record2 = pico_mdns_record_create(url, url1, (uint16_t)strlen(url1), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Create a totally different record */ - record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Add the records to the tree */ - pico_tree_insert(&MyRecords, record); - pico_tree_insert(&MyRecords, record1); - pico_tree_insert(&MyRecords, record2); - pico_tree_insert(&MyRecords, record3); - - fail_unless(1 == pico_mdns_my_records_claimed_id(1, &hits), - "mdns_my_records_claimed_id_failed!\n"); - fail_unless(2 == pico_tree_count(&hits), - "Vector count should be 2!\n"); - - fail_unless(0 == pico_mdns_my_records_claimed_id(0, &hits), - "Claim ID '0' isn't claimed yet.."); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_my_records_claimed) /* MARK: mdns_my_records_claimed */ -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, - *record3 = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata1 = { - long_be(0xFFFFFFFF) - }; - char url[] = "foo.local"; - char url1[] = "bar.local"; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record, "Record could not be created!\n"); - - /* Create 2 PTR records to URL */ - record1 = pico_mdns_record_create(url, url, (uint16_t) strlen(url), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record1, "Record could not be created!\n"); - record2 = pico_mdns_record_create(url, url1, (uint16_t) strlen(url1), - PICO_DNS_TYPE_PTR, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Create a totally different record */ - record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "Record could not be created!\n"); - - /* Add the records to the tree */ - pico_tree_insert(&MyRecords, record); - pico_tree_insert(&MyRecords, record1); - pico_tree_insert(&MyRecords, record2); - pico_tree_insert(&MyRecords, record3); - - pico_tree_insert(&rtree, record); - pico_tree_insert(&rtree, record1); - pico_tree_insert(&rtree, record2); - pico_tree_insert(&rtree, record3); - - ret = pico_mdns_my_records_claimed(rtree, callback, NULL); - fail_unless(0 == ret, "mdns_my_records_claimed failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -#if PICO_MDNS_ALLOW_CACHING == 1 -START_TEST(tc_mdns_cache_add_record) /* MARK: mdns_cache_add_record */ -{ - struct pico_mdns_record *record = NULL, *found = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - char url[] = "foo.local"; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 80, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record, "Record could not be created!\n"); - - ret = pico_mdns_cache_add_record(record); - fail_unless(0 == ret, - "mdns_cache_add_record returned error!\n"); - found = pico_tree_findKey(&Cache, record); - fail_if(found == NULL, "mdns_cache_add_record failed!\n"); - ret = pico_mdns_cache_add_record(record); - fail_unless(0 == ret, - "mdns_cache_add_record returned error!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -#endif -START_TEST(tc_pico_tree_merge) -{ - PICO_MDNS_RTREE_DECLARE(src); - PICO_MDNS_RTREE_DECLARE(dst); - fail_unless(pico_tree_merge(NULL, NULL) == -1); - fail_unless(pico_tree_merge(&dst, NULL) == -1); - fail_unless(pico_tree_merge(NULL, &src) == -1); - fail_unless(pico_tree_merge(&dst, &src) == 0); -} -END_TEST -START_TEST(tc_mdns_populate_answer_vector) /* MARK: mdns_popolate_antree */ -{ - PICO_MDNS_RTREE_DECLARE(rtree); - char value[] = "\3foo\5local"; - printf("*********************** starting %s * \n", __func__); - add_records(); - - rtree = pico_mdns_populate_antree(value, PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN); - - fail_unless(1 == pico_tree_count(&rtree), "mdns_populate_answer_vector failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_handle_data_as_questions) /* MARK: handle_data_as_questions */ -{ - pico_dns_packet *packet = NULL; - PICO_MDNS_RTREE_DECLARE(antree); - PICO_DNS_QTREE_DECLARE(qtree); - char qurl[] = "picotcp.com"; - char qurl2[] = "google.com"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - struct pico_ip4 rdata1 = { - long_be(0xFFFFFFFF) - }; - uint16_t len = 0; - uint8_t *ptr = NULL; - int ret = 0; - struct pico_dns_question *a = NULL, *b = NULL; - struct pico_mdns_record *record1 = NULL, *record2 = NULL; - - printf("*********************** starting %s * \n", __func__); - - /* Create a DNS query packet */ - a = pico_mdns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - PICO_MDNS_QUESTION_FLAG_UNICAST_RES, 0); - fail_if(!a, "dns_question_create failed!\n"); - pico_tree_insert(&qtree, a); - fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); - b = pico_mdns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, - 0, 0); - fail_if(!b, "dns_question_create failed!\n"); - pico_tree_insert(&qtree, b); - packet = pico_dns_query_create(&qtree, NULL, NULL, NULL, &len); - fail_if(packet == NULL, "mdns_query_create returned NULL!\n"); - - /* Create records for answers */ - record1 = pico_mdns_record_create(qurl, &rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record1, "mdns_record_create returned NULL!\n"); - record1->flags |= 0xC0; - record2 = pico_mdns_record_create(qurl2, &rdata1, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record2, "mdns_record_created returned NULL!\n"); - record2->flags |= 0xC0; - - /* Add them to my records */ - pico_tree_insert(&MyRecords, record1); - pico_tree_insert(&MyRecords, record2); - - ptr = ((uint8_t *)packet + 12); - - antree = pico_mdns_handle_data_as_questions(&ptr, 2, packet); - fail_unless(2 == pico_tree_count(&antree), - "pico_mdns_handle_data_as_questions returned error!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_handle_data_as_answers) /* MARK: handle_data_as_answers */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *a = NULL, *b = NULL; - char url[] = "picotcp.com"; - char url2[] = "google.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint8_t *ptr = NULL; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!a, "dns_record_create returned NULL!\n"); - b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_SHARED); - fail_if(!a, "dns_record_create returned NULL!\n"); - pico_tree_insert(&rtree, a->record); - pico_tree_insert(&rtree, b->record); - - /* Try to create an answer packet */ - packet = pico_dns_answer_create(&rtree, NULL, NULL, &len); - fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); - - ptr = ((uint8_t *)packet + 12); - - ret = pico_mdns_handle_data_as_answers_generic(&ptr, 2, packet, 0); - fail_unless(0 == ret, "mdns_handle_data_as_answers failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_handle_data_as_authorities) /* MARK: handle_data_as_authorities */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *a = NULL, *b = NULL; - char url[] = "picotcp.com"; - char url2[] = "google.com"; - uint16_t len = 0; - uint8_t *ptr = NULL; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!a, "dns_record_create returned NULL!\n"); - b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_SHARED); - fail_if(!a, "dns_record_create returned NULL!\n"); - pico_tree_insert(&rtree, a->record); - pico_tree_insert(&rtree, b->record); - - /* Try to create an answer packet */ - packet = pico_dns_answer_create(&rtree, NULL, NULL, &len); - fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); - - ptr = ((uint8_t *)packet + 12); - - ret = pico_mdns_handle_data_as_answers_generic(&ptr, 2, packet, 1); - fail_unless(0 == ret, "mdns_handle_data_as_answers failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_handle_data_as_additionals) /* MARK: handle_data_as_additionals */ -{ - printf("*********************** starting %s * \n", __func__); - /* Insert code here... */ - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_sort_unicast_multicast) /* MARK: sort_unicast_multicast */ -{ - PICO_MDNS_RTREE_DECLARE(antree); - PICO_DNS_RTREE_DECLARE(antree_u); - PICO_DNS_RTREE_DECLARE(antree_m); - struct pico_mdns_record *a = NULL, *b = NULL; - char url[] = "picotcp.com"; - char url2[] = "google.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!a, "mdns_record_create returned NULL!\n"); - b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - (PICO_MDNS_RECORD_SHARED | PICO_MDNS_RECORD_SEND_UNICAST)); - fail_if(!a, "mdns_record_create returned NULL!\n"); - pico_tree_insert(&antree, a); - pico_tree_insert(&antree, b); - - ret = pico_mdns_sort_unicast_multicast(&antree, &antree_u, &antree_m); - fail_unless(0 == ret, "mdns_sort_unicast_multicast returned error!\n"); - fail_unless(1 == pico_tree_count(&antree_u), "mdns_sort_unicast_multicast failed!\n"); - fail_unless(1 == pico_tree_count(&antree_m), "mdns_sort_unicast_multicast failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_gather_additionals) /* MARK: gather_additionals */ -{ - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - struct pico_mdns_record *srv_record = NULL, *record = NULL; - struct pico_tree_node *node = NULL; - int ret = 0; - char value[] = "\0\0\0\0\0\x50\4host\5local"; - printf("*********************** starting %s * \n", __func__); - - add_records(); - - srv_record = pico_mdns_record_create("test._http._tcp.local", - value, 17, - PICO_DNS_TYPE_SRV, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!srv_record, "Could not create SRV record!\n"); - pico_tree_insert(&antree, srv_record); - - ret = pico_mdns_gather_additionals(&antree, &artree); - fail_if(ret, "Gather Additionals returned error!\n"); - fail_unless(pico_tree_count(&antree) == 3, "ANtree should contain 3: %d", - pico_tree_count(&antree)); - - printf("Answers: \n"); - pico_tree_foreach(node, &antree) { - if ((record = node->keyValue)) { - printf("%d - %s\n", short_be(record->record->rsuffix->rtype), - record->record->rname); - } - } - - printf("Additionals: \n"); - pico_tree_foreach(node, &artree) { - if ((record = node->keyValue)) { - printf("%d - %s\n", short_be(record->record->rsuffix->rtype), - record->record->rname); - } - } - - fail_unless(pico_tree_count(&artree) == 3, "ARtree should contine 3: %d", - pico_tree_count(&artree)); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_apply_known_answer_suppression) /* MARK: apply_k_a_s */ -{ - pico_dns_packet *packet = NULL; - PICO_DNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *a = NULL, *b = NULL; - char url[] = "picotcp.com"; - char url2[] = "google.com"; - uint8_t rdata[4] = { - 10, 10, 0, 1 - }; - uint8_t *ptr = NULL; - uint16_t len = 0; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!a, "dns_record_create returned NULL!\n"); - b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, - PICO_MDNS_RECORD_SHARED); - fail_if(!a, "dns_record_create returned NULL!\n"); - - pico_tree_insert(&antree, a->record); - pico_tree_insert(&antree, b->record); - pico_tree_insert(&rtree, a); - pico_tree_insert(&rtree, b); - - /* Try to create an answer packet */ - packet = pico_dns_answer_create(&antree, NULL, NULL, &len); - fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); - - ptr = ((uint8_t *)packet + 12); - - printf("Applying Known answer suppression...\n"); - - ret = pico_mdns_apply_k_a_s(&rtree, packet, 1, &ptr); - fail_unless(0 == ret, "mdns_apply_known_answer_suppression returned error!\n"); - - fail_unless(1 == pico_tree_count(&rtree), - "mdns_apply_known_answer_suppression failed %d!\n", pico_tree_count(&rtree)); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_send_query_packet) /* MARK: send_query_packet */ -{ - struct pico_mdns_cookie cookie; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_COOKIE_DECLARE(a); - - struct pico_dns_question *question1 = NULL; - struct pico_dns_question *question2 = NULL; - char url1[] = "foo.local"; - uint16_t len; - printf("*********************** starting %s * \n", __func__); - - /* Create some questions */ - question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_A, - PICO_DNS_CLASS_IN, 0); - fail_if(!question1, "Could not create question 1!\n"); - question2 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, - PICO_DNS_TYPE_PTR, - PICO_DNS_CLASS_IN, 0); - pico_tree_insert(&(a.qtree), question1); - pico_tree_insert(&(a.qtree), question2); - cookie.count = 2; - - pico_stack_init(); - mdns_init(); - - pico_mdns_send_query_packet(0, &cookie); - cookie.type = PICO_MDNS_PACKET_TYPE_QUERY; - cookie.qtree = qtree; - pico_mdns_send_query_packet(0, &cookie); - cookie.type++; - cookie.status = PICO_MDNS_COOKIE_STATUS_CANCELLED; - pico_mdns_send_query_packet(0, &cookie); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_getrecord) /* MARK: getrecord */ -{ -#if PICO_MDNS_ALLOW_CACHING == 1 - struct pico_mdns_record *record = NULL, *found = NULL; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - char url[] = "foo.local"; -#endif - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - - /* - If caching is enabled: - If the record is cached: - getrecord should get the record from the cache, execute the callback and return 0 when the callback is finished. - Else: - getrecord should send a query and return 0 when the query is sent. - Else: - getrecord should send a query and return 0 when the query is sent. - */ - - /* Init */ - pico_stack_init(); - mdns_init(); - -#if PICO_MDNS_ALLOW_CACHING == 1 - /* Create an A record with URL */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 80, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record, "Record could not be created!\n"); - - ret = pico_mdns_cache_add_record(record); - fail_unless(0 == ret, - "mdns_cache_add_record returned error!\n"); - found = pico_tree_findKey(&Cache, record); - fail_if(found == NULL, "mdns_cache_add_record failed!\n"); -#endif - -#if PICO_MDNS_ALLOW_CACHING == 1 - amount_callback_executed = 0; - ret = pico_mdns_getrecord("foo.local", PICO_DNS_TYPE_A, callback, NULL); - fail_unless(1 == amount_callback_executed, "mdns_getrecord failed with cache record, callback not executed (%d) !\n", amount_callback_executed); - fail_unless(0 == ret, "mdns_getrecord failed with cache record!\n"); -#endif - - ret = pico_mdns_getrecord("bar.local", PICO_DNS_TYPE_A, callback, NULL); - fail_unless(0 == ret, "mdns_getrecord failed!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_send_announcement_packet) /* MARK: send_announcement_packet */ -{ - struct pico_mdns_cookie *cookie = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - - printf("*********************** starting %s * \n", __func__); - - cookie = pico_mdns_cookie_create(qtree, antree, artree, 2, - PICO_MDNS_PACKET_TYPE_ANNOUNCEMENT, - callback, NULL); - - pico_stack_init(); - mdns_init(); - - pico_mdns_send_announcement_packet(0, cookie); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_announce) /* MARK: annonce */ -{ - printf("*********************** starting %s * \n", __func__); - add_records(); - pico_stack_init(); - mdns_init(); - - fail_unless(0 == pico_mdns_announce(callback, NULL), - "mdns_announce failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_send_probe_packet) /* MARK: send_probe_packet */ -{ - struct pico_mdns_cookie *cookie = NULL; - PICO_DNS_QTREE_DECLARE(qtree); - PICO_MDNS_RTREE_DECLARE(antree); - PICO_MDNS_RTREE_DECLARE(artree); - - printf("*********************** starting %s * \n", __func__); - - cookie = pico_mdns_cookie_create(qtree, antree, artree, 2, - PICO_MDNS_PACKET_TYPE_PROBE, - callback, NULL); - - pico_stack_init(); - mdns_init(); - - pico_mdns_send_probe_packet(0, cookie); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_add_probe_question) /* MARK: add_probe_question */ -{ - PICO_DNS_QTREE_DECLARE(qtree); - int ret = 0; - char arg[] = "\4host\5local"; - char arg1[] = "\4tree\5local"; - char arg2[] = "\x8host (2)\5local"; - printf("*********************** starting %s * \n", __func__); - ret = pico_mdns_add_probe_question(&qtree, arg); - fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); - fail_unless(1 == pico_tree_count(&qtree), - "New probe question didn't create!\n"); - ret = pico_mdns_add_probe_question(&qtree, arg); - fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); - fail_unless(1 == pico_tree_count(&qtree), - "Count should be 1, is: %d!\n", pico_tree_count(&qtree)); - ret = pico_mdns_add_probe_question(&qtree, arg1); - fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); - fail_unless(2 == pico_tree_count(&qtree), - "New probe question didn't create!\n"); - ret = pico_mdns_add_probe_question(&qtree, arg2); - fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); - fail_unless(3 == pico_tree_count(&qtree), - "New probe question didn't create!\n"); - PICO_DNS_QTREE_DESTROY(&qtree); - fail_unless(0 == pico_tree_count(&qtree), - "Tree isn't properly destroyed %d!\n", pico_tree_count(&qtree)); - ret = pico_mdns_add_probe_question(&qtree, arg2); - fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); - fail_unless(1 == pico_tree_count(&qtree), - "New probe question didn't create!\n"); - PICO_DNS_QTREE_DESTROY(&qtree); - fail_unless(0 == pico_tree_count(&qtree), - "Tree isn't properly destroyed the second time!\n"); - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_probe) /* MARK: probe */ -{ - printf("*********************** starting %s * \n", __func__); - add_records(); - pico_stack_init(); - mdns_init(); - - fail_unless(0 == pico_mdns_probe(callback, NULL), - "mdns_announce failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_claim) /* MARK: mdns_claim */ -{ - PICO_MDNS_RTREE_DECLARE(rtree); - struct pico_mdns_record *record = NULL, *record1 = NULL; - char url[] = "foo.local"; - char url2[] = "bar.local"; - struct pico_ip4 rdata = { - long_be(0x00FFFFFF) - }; - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - /* Create a record */ - record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record, "Record could not be created!\n"); - record1 = pico_mdns_record_create(url2, &rdata, 4, PICO_DNS_TYPE_A, 0, - PICO_MDNS_RECORD_UNIQUE); - fail_if(!record1, "Record could not be created!\n"); - - /* Some tests */ - pico_tree_insert(&rtree, record); - pico_tree_insert(&rtree, record1); - - pico_stack_init(); - mdns_init(); - - ret = pico_mdns_claim(rtree, callback, NULL); - fail_unless(0 == ret, "mdns_claimed failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_tryclaim_hostname) /* MARK: tryclaim_hostname */ -{ - int ret = 0; - - printf("*********************** starting %s * \n", __func__); - pico_stack_init(); - mdns_init(); - - ret = pico_mdns_tryclaim_hostname("test.local", NULL); - fail_unless(0 == ret, "mdns_tryclaim_hostname failed!\n"); - - printf("*********************** ending %s * \n", __func__); -} -END_TEST -START_TEST(tc_mdns_get_hostname) /* MARK: get_hostname */ -{ - const char *c_hostname; - printf("*********************** starting %s * \n", __func__); - pico_stack_init(); - mdns_init(); - - c_hostname = pico_mdns_get_hostname(); - printf(" hostname %s\n", c_hostname); - printf("*********************** ending %s * \n", __func__); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_mdns_init = tcase_create("Unit test for mdns_init"); - - /* Comparing functions */ - TCase *TCase_mdns_record_cmp = tcase_create("Unit test for mdns_record_cmp"); - TCase *TCase_mdns_record_cmp_name_type = tcase_create("Unit test for mdns_record_cmp_name_type"); - TCase *TCase_mdns_cookie_cmp = tcase_create("Unit test for mdns_cookie_cmp"); - - TCase *TCase_mdns_suffix_to_uint16 = tcase_create("Unit test for mdns_suffix_to_uint16"); - - /* Cookie functions */ - TCase *TCase_mdns_cookie_delete = tcase_create("Unit test for mdns_cookie_delete"); - TCase *TCase_mdns_cookie_create = tcase_create("Unit test for mdns_cookie_create"); - TCase *TCase_mdns_cookie_tree_find_query_cookie = tcase_create("Unit test for mdns_cookie_tree_find_query_cookie"); - TCase *TCase_mdns_cookie_apply_spt = tcase_create("Unit test for mdns_cookie_apply_spt"); - TCase *TCase_mdns_is_suffix_present = tcase_create("Unit test for mdns_is_suffix_present"); - TCase *TCase_pico_itoa = tcase_create("Unit test for pico_itoa"); - TCase *TCase_mdns_resolve_name_conflict = tcase_create("Unit test for mdns_resolve_name_conflict"); - TCase *TCase_mdns_generate_new_records = tcase_create("Unit test for mdns_generate_new_records"); - TCase *TCase_mdns_cookie_resolve_conflict = tcase_create("Unit test for mdns_cookie_resolve_conflict"); - - /* Question functions */ - TCase *TCase_mdns_question_create = tcase_create("Unit test for mdns_question_create"); - - /* Record functions */ - TCase *TCase_mdns_record_resolve_conflict = tcase_create("Unit test for mdns_record_resolve_conflict"); - TCase *TCase_mdns_record_am_i_lexi_later = tcase_create("Unit test for mdns_record_am_i_lexi_later"); - TCase *TCase_mdns_record_copy_with_new_name = tcase_create("Unit test for mdns_record_copy"); - TCase *TCase_mdns_record_copy = tcase_create("Unit test for mdns_record_copy"); - TCase *TCase_mdns_record_create = tcase_create("Unit test for mdns_record_create"); - TCase *TCase_mdns_record_delete = tcase_create("Unit test for mdns_record_delete"); - - - /* Record tree functions */ - TCase *TCase_mdns_record_tree_find_name = tcase_create("Unit test for mdns_record_tree_find_name"); - TCase *TCase_mdns_record_tree_find_name_type = tcase_create("Unit test for mdns_record_tree_find_name_type"); - TCase *TCase_mdns_record_tree_del_name = tcase_create("Unit test for mdns_record_tree_del_name"); - TCase *TCase_mdns_record_tree_del_name_type = tcase_create("Unit test for mdns_record_tree_del_name_type"); - - /* My record functions */ - TCase *TCase_mdns_my_records_add = tcase_create("Unit test for mdns_my_records_add"); - TCase *TCase_mdns_my_records_find_probed = tcase_create("Unit test for mdns_my_records_find_probed"); - TCase *TCase_mdns_my_records_find_to_probe = tcase_create("Unit test for mdns_my_records_find_to_probe"); - TCase *TCase_mdns_my_records_claimed_id = tcase_create("Unit test for mdns_my_records_claimed_id"); - TCase *TCase_mdns_my_records_claimed = tcase_create("Unit test for mdns_my_records_claimed"); - - /* Cache functions */ - TCase *TCase_mdns_cache_add_record = tcase_create("Unit test for mdns_cache_add_record"); - - /* Handling receptions */ - TCase *TCase_mdns_populate_answer_vector = tcase_create("Unit test for mdns_populate_answer_vector"); - TCase *TCase_mdns_handle_data_as_questions = tcase_create("Unit test for mdns_handle_data_as_questions"); - TCase *TCase_mdns_handle_data_as_answers = tcase_create("Unit test for mdns_handle_data_as_answers"); - TCase *TCase_mdns_handle_data_as_authorities = tcase_create("Unit test for mdns_handle_data_as_authorities"); - TCase *TCase_mdns_handle_data_as_additionals = tcase_create("Unit test for mdns_handle_data_as_additionals"); - - /* Handling query packets */ - TCase *TCase_mdns_sort_unicast_multicast = tcase_create("Unit test for mdns_sort_unicast_multicast"); - TCase *TCase_mdns_gather_additionals = tcase_create("Unit test for mdns_gather_additionals"); - TCase *TCase_mdns_apply_known_answer_suppression = tcase_create("Unit test for mdns_apply_known_answer_suppression"); - - /* Address resolving functions */ - TCase *TCase_mdns_send_query_packet = tcase_create("Unit test for mdns_send_query_packet"); - TCase *TCase_mdns_getrecord = tcase_create("Unit test for mdns_getrecord"); - - /* Probe & Announcement functions */ - TCase *TCase_mdns_send_announcement_packet = tcase_create("Unit test for mdns_send_announcement_packet"); - TCase *TCase_mdns_announce = tcase_create("Unit test for mdns_announce"); - TCase *TCase_mdns_send_probe_packet = tcase_create("Unit test for mdns_send_probe_packet"); - TCase *TCase_mdns_add_probe_question = tcase_create("Unit test for mdns_add_probe_question"); - TCase *TCase_mdns_probe = tcase_create("Unit test for mdns_probe"); - - /* Claiming functions */ - TCase *TCase_mdns_claim = tcase_create("Unit test for mnds_claim"); - - /* API functions */ - TCase *TCase_mdns_tryclaim_hostname = tcase_create("Unit test for mdns_tryclaim_hostname"); - TCase *TCase_mdns_get_hostname = tcase_create("Unit test for mdns_get_hostname"); - - TCase *TCase_pico_tree_merge = tcase_create("Unit test for pico_tree_merge"); - - tcase_add_test(TCase_mdns_init, tc_mdns_init); - suite_add_tcase(s, TCase_mdns_init); - - /* Comparing functions */ - tcase_add_test(TCase_mdns_record_cmp, tc_mdns_record_cmp); - suite_add_tcase(s, TCase_mdns_record_cmp); - tcase_add_test(TCase_mdns_record_cmp_name_type, tc_mdns_record_cmp_name_type); - suite_add_tcase(s, TCase_mdns_record_cmp_name_type); - tcase_add_test(TCase_mdns_cookie_cmp, tc_mdns_cookie_cmp); - suite_add_tcase(s, TCase_mdns_cookie_cmp); - - tcase_add_test(TCase_mdns_suffix_to_uint16, tc_mdns_suffix_to_uint16); - suite_add_tcase(s, TCase_mdns_suffix_to_uint16); - - /* Cookie functions */ - tcase_add_test(TCase_mdns_cookie_delete, tc_mdns_cookie_delete); - suite_add_tcase(s, TCase_mdns_cookie_delete); - tcase_add_test(TCase_mdns_cookie_create, tc_mdns_cookie_create); - suite_add_tcase(s, TCase_mdns_cookie_create); - tcase_add_test(TCase_mdns_cookie_tree_find_query_cookie, tc_mdns_cookie_tree_find_query_cookie); - suite_add_tcase(s, TCase_mdns_cookie_tree_find_query_cookie); - tcase_add_test(TCase_mdns_cookie_apply_spt, tc_mdns_cookie_apply_spt); - suite_add_tcase(s, TCase_mdns_cookie_apply_spt); - tcase_add_test(TCase_mdns_is_suffix_present, tc_mdns_is_suffix_present); - suite_add_tcase(s, TCase_mdns_is_suffix_present); - tcase_add_test(TCase_pico_itoa, tc_pico_itoa); - suite_add_tcase(s, TCase_pico_itoa); - tcase_add_test(TCase_mdns_resolve_name_conflict, tc_mdns_resolve_name_conflict); - suite_add_tcase(s, TCase_mdns_resolve_name_conflict); - tcase_add_test(TCase_mdns_generate_new_records, tc_mdns_generate_new_records); - suite_add_tcase(s, TCase_mdns_generate_new_records); - tcase_add_test(TCase_mdns_cookie_resolve_conflict, tc_mdns_cookie_resolve_conflict); - suite_add_tcase(s, TCase_mdns_cookie_resolve_conflict); - - /* Question functions */ - tcase_add_test(TCase_mdns_question_create, tc_mdns_question_create); - suite_add_tcase(s, TCase_mdns_question_create); - - /* Record functions */ - tcase_add_test(TCase_mdns_record_resolve_conflict, tc_mdns_record_resolve_conflict); - suite_add_tcase(s, TCase_mdns_record_resolve_conflict); - tcase_add_test(TCase_mdns_record_am_i_lexi_later, tc_mdns_record_am_i_lexi_later); - suite_add_tcase(s, TCase_mdns_record_am_i_lexi_later); - tcase_add_test(TCase_mdns_record_copy_with_new_name, tc_mdns_record_copy_with_new_name); - suite_add_tcase(s, TCase_mdns_record_copy_with_new_name); - tcase_add_test(TCase_mdns_record_copy, tc_mdns_record_copy); - suite_add_tcase(s, TCase_mdns_record_copy); - tcase_add_test(TCase_mdns_record_create, tc_mdns_record_create); - suite_add_tcase(s, TCase_mdns_record_create); - tcase_add_test(TCase_mdns_record_delete, tc_mdns_record_delete); - suite_add_tcase(s, TCase_mdns_record_delete); - - /* Record tree functions */ - tcase_add_test(TCase_mdns_record_tree_find_name, tc_mdns_record_tree_find_name); - suite_add_tcase(s, TCase_mdns_record_tree_find_name); - tcase_add_test(TCase_mdns_record_tree_find_name_type, tc_mdns_record_tree_find_name_type); - suite_add_tcase(s, TCase_mdns_record_tree_find_name_type); - tcase_add_test(TCase_mdns_record_tree_del_name, tc_mdns_record_tree_del_name); - suite_add_tcase(s, TCase_mdns_record_tree_del_name); - tcase_add_test(TCase_mdns_record_tree_del_name_type, tc_mdns_record_tree_del_name_type); - suite_add_tcase(s, TCase_mdns_record_tree_del_name_type); - - /* My records functions */ - tcase_add_test(TCase_mdns_my_records_add, tc_mdns_my_records_add); - suite_add_tcase(s, TCase_mdns_my_records_add); - tcase_add_test(TCase_mdns_my_records_find_probed, tc_mdns_my_records_find_probed); - suite_add_tcase(s, TCase_mdns_my_records_find_probed); - tcase_add_test(TCase_mdns_my_records_find_to_probe, tc_mdns_my_records_find_to_probe); - suite_add_tcase(s, TCase_mdns_my_records_find_to_probe); - tcase_add_test(TCase_mdns_my_records_claimed_id, tc_mdns_my_records_claimed_id); - suite_add_tcase(s, TCase_mdns_my_records_claimed_id); - tcase_add_test(TCase_mdns_my_records_claimed, tc_mdns_my_records_claimed); - suite_add_tcase(s, TCase_mdns_my_records_claimed); - - /* Cache functions */ - tcase_add_test(TCase_mdns_cache_add_record, tc_mdns_cache_add_record); - suite_add_tcase(s, TCase_mdns_cache_add_record); - tcase_add_test(TCase_mdns_populate_answer_vector, tc_mdns_populate_answer_vector); - suite_add_tcase(s, TCase_mdns_populate_answer_vector); - - /* Handling receptions */ - tcase_add_test(TCase_mdns_handle_data_as_questions, tc_mdns_handle_data_as_questions); - suite_add_tcase(s, TCase_mdns_handle_data_as_questions); - tcase_add_test(TCase_mdns_handle_data_as_answers, tc_mdns_handle_data_as_answers); - suite_add_tcase(s, TCase_mdns_handle_data_as_answers); - tcase_add_test(TCase_mdns_handle_data_as_authorities, tc_mdns_handle_data_as_authorities); - suite_add_tcase(s, TCase_mdns_handle_data_as_authorities); - tcase_add_test(TCase_mdns_handle_data_as_additionals, tc_mdns_handle_data_as_additionals); - suite_add_tcase(s, TCase_mdns_handle_data_as_additionals); - - /* Handling query packets */ - tcase_add_test(TCase_mdns_sort_unicast_multicast, tc_mdns_sort_unicast_multicast); - suite_add_tcase(s, TCase_mdns_sort_unicast_multicast); - tcase_add_test(TCase_mdns_gather_additionals, tc_mdns_gather_additionals); - suite_add_tcase(s, TCase_mdns_gather_additionals); - tcase_add_test(TCase_mdns_apply_known_answer_suppression, tc_mdns_apply_known_answer_suppression); - suite_add_tcase(s, TCase_mdns_apply_known_answer_suppression); - - /* Address resolving functions */ - tcase_add_test(TCase_mdns_send_query_packet, tc_mdns_send_query_packet); - suite_add_tcase(s, TCase_mdns_send_query_packet); - tcase_add_test(TCase_mdns_getrecord, tc_mdns_getrecord); - suite_add_tcase(s, TCase_mdns_getrecord); - - /* Probe & Announcement functions */ - tcase_add_test(TCase_mdns_send_announcement_packet, tc_mdns_send_announcement_packet); - suite_add_tcase(s, TCase_mdns_send_announcement_packet); - tcase_add_test(TCase_mdns_announce, tc_mdns_announce); - suite_add_tcase(s, TCase_mdns_announce); - tcase_add_test(TCase_mdns_send_probe_packet, tc_mdns_send_probe_packet); - suite_add_tcase(s, TCase_mdns_send_probe_packet); - tcase_add_test(TCase_mdns_add_probe_question, tc_mdns_add_probe_question); - suite_add_tcase(s, TCase_mdns_add_probe_question); - tcase_add_test(TCase_mdns_probe, tc_mdns_probe); - suite_add_tcase(s, TCase_mdns_probe); - - /* Claiming functions */ - tcase_add_test(TCase_mdns_claim, tc_mdns_claim); - suite_add_tcase(s, TCase_mdns_claim); - - /* API functions */ - tcase_add_test(TCase_mdns_tryclaim_hostname, tc_mdns_tryclaim_hostname); - suite_add_tcase(s, TCase_mdns_tryclaim_hostname); - tcase_add_test(TCase_mdns_get_hostname, tc_mdns_get_hostname); - suite_add_tcase(s, TCase_mdns_get_hostname); - - tcase_add_test(TCase_pico_tree_merge, tc_pico_tree_merge); - suite_add_tcase(s, TCase_pico_tree_merge); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} - diff --git a/ext/picotcp/test/unit/modunit_pico_mld.c b/ext/picotcp/test/unit/modunit_pico_mld.c deleted file mode 100644 index 5b17c1a..0000000 --- a/ext/picotcp/test/unit/modunit_pico_mld.c +++ /dev/null @@ -1,584 +0,0 @@ -#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" -#include "modules/pico_mld.c" -#include "check.h" -#include "pico_dev_null.c" - -Suite *pico_suite(void); -void mock_callback(struct mld_timer *t); - -static uint32_t timers_added = 0; -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(expire); - IGNORE_PARAMETER(timer); - IGNORE_PARAMETER(arg); - return ++timers_added; -} -void mock_callback(struct mld_timer *t) -{ - IGNORE_PARAMETER(t); -} -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)); -} -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)); -} -static PICO_TREE_DECLARE(_MCASTFilter, mcast_filter_cmp_ipv6); - -START_TEST(tc_pico_mld_fill_hopbyhop) -{ - struct pico_ipv6_hbhoption *hbh = NULL; - /* Not-null case tested by unit_ipv6.c */ - fail_if(pico_mld_fill_hopbyhop(hbh) != NULL); -} -END_TEST -START_TEST(tc_pico_mld_check_hopbyhop) -{ - struct pico_ipv6_hbhoption *hbh = NULL; - struct pico_ipv6_hbhoption _hbh; - uint8_t *p; - 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 = 0; - int test = 0; - fail_if(pico_mld_check_hopbyhop(hbh) != -1); - _hbh.type = 1; - _hbh.len = 0; - fail_if(pico_mld_check_hopbyhop(&_hbh) != -1); - _hbh.type = PICO_PROTO_ICMP6; - _hbh.len = 1; - fail_if(pico_mld_check_hopbyhop(&_hbh) != -1); - - hbh = (struct pico_ipv6_hbhoption *) PICO_ZALLOC(sizeof(struct pico_ipv6_hbhoption) + 7); - hbh->type = PICO_PROTO_ICMP6; - hbh->len = 0; - for(test = 0; test < 7; test++) { - p = (uint8_t *)hbh + sizeof(struct pico_ipv6_hbhoption); - for(i = 0; i < 6; i++ ) { - if(i != test) - *(p++) = options[i + 2]; - else - *(p++) = 9; - } - if(test != 6) - fail_if(pico_mld_check_hopbyhop(hbh) != -1); - else - fail_if(pico_mld_check_hopbyhop(hbh) != 0); - } -} -END_TEST -START_TEST(tc_pico_mld_v1querier_expired) -{ - struct mld_timer *t = PICO_ZALLOC(sizeof(struct mld_timer)); - struct pico_ip6 addr = {{0}}; - struct pico_device *dev = pico_null_create("dummy2"); - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_frame)); - t->f = f; - pico_string_to_ipv6("AAAA::109", addr.addr); - /* void function, just check for side effects */ - /* No link */ - pico_mld_v1querier_expired(t); - f->dev = dev; - pico_ipv6_link_add(dev, addr, addr); - pico_mld_v1querier_expired(t); -} -END_TEST -START_TEST(tc_pico_mld_send_report) -{ - struct pico_frame *f; - struct pico_device *dev = pico_null_create("dummy1"); - struct pico_ip6 addr; - struct pico_ipv6_link *link; - struct mcast_parameters p; - f = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, sizeof(struct mldv2_report) + MLD_ROUTER_ALERT_LEN + sizeof(struct mldv2_group_record) + (0 * sizeof(struct pico_ip6))); - pico_string_to_ipv6("AAAA::110", addr.addr); - p.mcast_link.ip6 = addr; - /* No link */ - fail_if(pico_mld_send_report(&p, f) != -1); - link = pico_ipv6_link_add(dev, addr, addr); - p.event = 0; - link->mcast_compatibility = PICO_MLDV1; - fail_if(pico_mld_send_report(&p, f) != 0); - link->mcast_compatibility = 99; - fail_if(pico_mld_send_report(&p, f) != -1); -} -END_TEST -START_TEST(tc_pico_mld_report_expired) -{ - struct mld_timer *t = PICO_ZALLOC(sizeof(struct mld_timer)); - struct pico_ip6 zero = {0}; - - t->mcast_link = zero; - t->mcast_group = zero; - /* void function, just check for side effects */ - pico_mld_report_expired(t); -} -END_TEST -START_TEST(tc_pico_mld_delete_parameter) -{ - struct mcast_parameters p; - fail_if(pico_mld_delete_parameter(&p) != -1); -} -END_TEST -START_TEST(tc_mldt_type_compare) -{ - struct mld_timer a; - struct mld_timer b; - a.type = 1; - b.type = 2; - fail_if(mldt_type_compare(&a, &b) != -1); - fail_if(mldt_type_compare(&b, &a) != 1); - fail_if(mld_timer_cmp(&b, &a) != 1); -} -END_TEST -START_TEST(tc_pico_mld_is_checksum_valid) -{ - struct pico_frame *f; - f = pico_proto_ipv6.alloc(&pico_proto_ipv6, NULL, sizeof(struct mldv2_report) + MLD_ROUTER_ALERT_LEN + sizeof(struct mldv2_group_record) + (0 * sizeof(struct pico_ip6))); - fail_if(pico_mld_is_checksum_valid(f) == 1); -} -END_TEST -START_TEST(tc_pico_mld_find_parameter) -{ - struct pico_ip6 mcast_link, mcast_group; - struct mcast_parameters test = { - 0 - }; - fail_if(pico_mld_find_parameter(NULL, NULL) != NULL); - pico_string_to_ipv6("AAAA::111", mcast_link.addr); - fail_if(pico_mld_find_parameter(&mcast_link, NULL) != NULL); - pico_string_to_ipv6("AAAA::211", mcast_group.addr); - fail_if(pico_mld_find_parameter(&mcast_link, &mcast_group) != NULL); - test.mcast_link.ip6 = mcast_link; - test.mcast_group.ip6 = mcast_group; - pico_tree_insert(&MLDParameters, &test); - - fail_if(pico_mld_find_parameter(&mcast_link, &mcast_group) == NULL); - pico_tree_delete(&MLDParameters, &test); -} -END_TEST -START_TEST(tc_pico_mld_timer_expired) -{ - struct mld_timer *t, *s; - t = PICO_ZALLOC(sizeof(struct mld_timer)); - t->stopped = MLD_TIMER_STOPPED; - t->type = 0; - pico_string_to_ipv6("AAAA::112", t->mcast_link.addr); - pico_string_to_ipv6("AAAA::112", t->mcast_group.addr); - /* void function, just check for side effects */ - pico_mld_timer_expired(0, (void *)t); - pico_tree_insert(&MLDTimers, t); - s = PICO_ZALLOC(sizeof(struct mld_timer)); - memcpy(s, t, sizeof(struct mld_timer)); /* t will be freed next test */ - pico_mld_timer_expired(0, (void *)t); /* will be freed */ - s->stopped++; - s->start = PICO_TIME_MS() * 2; - s->type++; - pico_tree_insert(&MLDTimers, s); - t = PICO_ZALLOC(sizeof(struct mld_timer)); - memcpy(t, s, sizeof(struct mld_timer)); /* s will be freed next test */ - pico_mld_timer_expired(0, (void *)s); /* s will be freed */ - t->mld_callback = mock_callback; - pico_mld_timer_expired(0, (void *)t); /* t will be freed */ -} -END_TEST -START_TEST(tc_pico_mld_send_done) -{ - struct mcast_parameters p; - fail_if(pico_mld_send_done(&p, NULL) != 0); -} -END_TEST -START_TEST(tc_mld_stsdifs) -{ - struct mcast_parameters *p; - struct pico_device *dev = pico_null_create("dummy3"); - struct pico_ipv6_link *link; - struct mld_timer *t = PICO_ZALLOC(sizeof(struct mld_timer)); - /* Building example frame */ - p = PICO_ZALLOC(sizeof(struct mcast_parameters)); - pico_string_to_ipv6("AAAA::113", p->mcast_link.ip6.addr); - pico_string_to_ipv6("FF00::e007:707", p->mcast_group.ip6.addr); - /* no link */ - fail_if(mld_stsdifs(p) != -1); - link = pico_ipv6_link_add(dev, p->mcast_link.ip6, p->mcast_link.ip6); - link->mcast_compatibility = PICO_MLDV1; - /* no timer */ - fail_if(mld_stsdifs(p) != -1); - t->type = MLD_TIMER_GROUP_REPORT; - t->mcast_link = p->mcast_link.ip6; - t->mcast_group = p->mcast_group.ip6; - pico_tree_insert(&MLDTimers, t); - fail_if(mld_stsdifs(p) != 0); - /* set flag */ - pico_mld_flag = 1; - fail_if(mld_stsdifs(p) != 0); -} -END_TEST -START_TEST(tc_mld_srsf) -{ - struct mcast_parameters *p; - /* Building example frame */ - - p = PICO_ZALLOC(sizeof(struct mcast_parameters)); - pico_string_to_ipv6("AAAA::114", p->mcast_link.ip6.addr); - pico_string_to_ipv6("FF00::e007:707", p->mcast_group.ip6.addr); - fail_if(mld_srsf(p) != -1); -} -END_TEST - -START_TEST(tc_mld_srst) -{ - struct mcast_parameters *p; - struct pico_device *dev = pico_null_create("dummy3"); - struct pico_ipv6_link *link; - struct pico_mcast_group g; - /* Building example frame */ - - p = PICO_ZALLOC(sizeof(struct mcast_parameters)); - pico_string_to_ipv6("AAAA::99", p->mcast_link.ip6.addr); - pico_string_to_ipv6("FF00::e007:707", p->mcast_group.ip6.addr); - p->MCASTFilter = &_MCASTFilter; - p->filter_mode = 0; - g.filter_mode = 0; - g.mcast_addr = p->mcast_group; - g.MCASTSources.root = &LEAF; - g.MCASTSources.compare = mcast_sources_cmp_ipv6; - - pico_tree_insert(&MLDParameters, p); - /* no link */ - fail_if(mld_srst(p) != -1); - link = pico_ipv6_link_add(dev, p->mcast_link.ip6, p->mcast_link.ip6); - link->mcast_compatibility = PICO_MLDV1; - /* invalid proto */ - fail_if(mld_srst(p) != -1); - link->mcast_compatibility = PICO_MLDV2; - pico_tree_insert(link->MCASTGroups, &g); - - fail_if(mld_srst(p) != 0); - pico_tree_delete(&MLDParameters, p); -} -END_TEST -START_TEST(tc_mld_mrsrrt) -{ - struct mcast_parameters *p; - struct pico_device *dev = pico_null_create("dummy3"); - struct pico_ipv6_link *link; - /* Building example frame */ - p = PICO_ZALLOC(sizeof(struct mcast_parameters)); - pico_string_to_ipv6("AAAA::115", p->mcast_link.ip6.addr); - pico_string_to_ipv6("FF00::e007:707", p->mcast_group.ip6.addr); - /* no link */ - fail_if(mld_mrsrrt(p) != -1); - link = pico_ipv6_link_add(dev, p->mcast_link.ip6, p->mcast_link.ip6); - link->mcast_compatibility = PICO_MLDV1; - /* wrong proto */ - fail_if(mld_mrsrrt(p) != -1); - link->mcast_compatibility = PICO_MLDV2; - p->f = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, sizeof(struct mldv2_report) + MLD_ROUTER_ALERT_LEN + sizeof(struct mldv2_group_record) + (0 * sizeof(struct pico_ip6))); - fail_if(mld_mrsrrt(p) != -1); - -} -END_TEST -START_TEST(tc_pico_mld_process_in) -{ - struct mcast_parameters *p; - struct pico_device *dev = pico_null_create("dummy3"); - struct pico_ipv6_link *link; - uint8_t i, j, _i, _j; - int result = 0; - struct pico_mcast_group g; - struct mldv2_report *report; - /* Building example frame */ - p = PICO_ZALLOC(sizeof(struct mcast_parameters)); - pico_string_to_ipv6("AAAA::101", p->mcast_link.ip6.addr); - pico_string_to_ipv6("FF00::e007:707", p->mcast_group.ip6.addr); - /* no link */ - fail_if(pico_mld_generate_report(p) != -1); - link = pico_ipv6_link_add(dev, p->mcast_link.ip6, p->mcast_link.ip6); - pico_string_to_ipv6("AAAA::100", p->mcast_group.ip6.addr); - fail_if(pico_mld_generate_report(p) != -1); - pico_string_to_ipv6("FF00::e007:707", p->mcast_group.ip6.addr); - link->mcast_compatibility = PICO_MLDV1; - g.mcast_addr = p->mcast_group; - g.MCASTSources.root = &LEAF; - g.MCASTSources.compare = mcast_sources_cmp_ipv6; - /* No mcastsources tree */ - link->mcast_compatibility = PICO_MLDV2; - fail_if(pico_mld_generate_report(p) != -1); - pico_tree_insert(link->MCASTGroups, &g); - pico_tree_insert(&MLDParameters, p); - - link->mcast_compatibility = 99; - fail_if(pico_mld_generate_report(p) != -1); - link->mcast_compatibility = PICO_MLDV1; - fail_if(pico_mld_generate_report(p) != 0); - link->mcast_compatibility = PICO_MLDV2; - for(_j = 0; _j < 3; _j++) { /* FILTER */ - (_j == 2) ? (result = -1) : (result = 0); - for(_i = 0; _i < 3; _i++) { /* FILTER */ - if(_i == 2) result = -1; - - for(i = 0; i < 3; i++) { /* STATES */ - for(j = 0; j < 6; j++) { /* EVENTS */ - p->MCASTFilter = &_MCASTFilter; - p->filter_mode = _i; - g.filter_mode = _j; - if(p->event == MLD_EVENT_DELETE_GROUP || p->event == MLD_EVENT_QUERY_RECV) - p->event++; - - fail_if(pico_mld_generate_report(p) != result); - p->state = i; - p->event = j; - if(result != -1 && p->f) { /* in some combinations, no frame is created */ - report = (struct mldv2_report *)(p->f->transport_hdr + MLD_ROUTER_ALERT_LEN); - report->crc = short_be(pico_icmp6_checksum(p->f)); - fail_if(pico_mld_process_in(p->f) != 0); - } - } - } - } - } - pico_tree_delete(&MLDParameters, p); - -} -END_TEST -START_TEST(tc_mld_rtimrtct) -{ - struct mld_timer *t = PICO_ZALLOC(sizeof(struct mld_timer)); - struct mcast_parameters p; - pico_string_to_ipv6("AAAA::102", t->mcast_link.addr); - pico_string_to_ipv6("AAAA::102", t->mcast_group.addr); - p.mcast_link.ip6 = t->mcast_link; - p.mcast_group.ip6 = t->mcast_group; - t->type = MLD_TIMER_GROUP_REPORT; - /* not in tree */ - fail_if(mld_rtimrtct(&p) != -1); - pico_mld_timer_start(t); - fail_if(mld_rtimrtct(&p) != 0); -} -END_TEST - -START_TEST(tc_mld_stcl) -{ - struct mld_timer *t = PICO_ZALLOC(sizeof(struct mld_timer)); - struct mcast_parameters p; - pico_string_to_ipv6("AAAA::103", t->mcast_link.addr); - pico_string_to_ipv6("AAAA::103", t->mcast_group.addr); - p.mcast_link.ip6 = t->mcast_link; - p.mcast_group.ip6 = t->mcast_group; - t->type = MLD_TIMER_GROUP_REPORT; - /* not in tree */ - fail_if(mld_stcl(&p) != -1); - pico_mld_timer_start(t); - fail_if(mld_stcl(&p) != 0); -} -END_TEST -START_TEST(tc_pico_mld_compatibility_mode) -{ - struct pico_frame *f; - struct pico_device *dev = pico_null_create("dummy1"); - struct pico_ip6 addr; - - f = pico_proto_ipv6.alloc(&pico_proto_ipv6, NULL, sizeof(struct mldv2_report) + MLD_ROUTER_ALERT_LEN + sizeof(struct mldv2_group_record) + (0 * sizeof(struct pico_ip6))); - pico_string_to_ipv6("AAAA::104", addr.addr); - /* No link */ - fail_if(pico_mld_compatibility_mode(f) != -1); - pico_ipv6_link_add(dev, addr, addr); - f->dev = dev; - /* MLDv2 query */ - f->buffer_len = 28 + PICO_SIZE_IP6HDR + MLD_ROUTER_ALERT_LEN; - fail_if(pico_mld_compatibility_mode(f) != 0); - /* MLDv1 query */ - f->buffer_len = 24 + PICO_SIZE_IP6HDR + MLD_ROUTER_ALERT_LEN; - fail_if(pico_mld_compatibility_mode(f) != 0); - /* Invalid Query */ - f->buffer_len = 25 + PICO_SIZE_IP6HDR + MLD_ROUTER_ALERT_LEN; - fail_if(pico_mld_compatibility_mode(f) == 0); - /* MLDv2 query + timer amready running */ - f->dev = dev; - f->buffer_len = 28 + PICO_SIZE_IP6HDR + MLD_ROUTER_ALERT_LEN + PICO_SIZE_ETHHDR; - fail_if(pico_mld_compatibility_mode(f) != -1); -} -END_TEST -START_TEST(tc_pico_mld_timer_reset) -{ - struct mld_timer *t = PICO_ZALLOC(sizeof(struct mld_timer)); - pico_string_to_ipv6("AAAA::105", t->mcast_link.addr); - pico_string_to_ipv6("AAAA::105", t->mcast_group.addr); - t->type = 0; - fail_if(pico_mld_timer_reset(t) != -1); -} -END_TEST -START_TEST(tc_pico_mld_state_change) -{ - struct pico_ip6 mcast_link, mcast_group; - struct mcast_parameters p; - pico_string_to_ipv6("AAAA::106", mcast_link.addr); - pico_string_to_ipv6("AAAA::106", mcast_group.addr); - p.mcast_link.ip6 = mcast_link; - p.mcast_group.ip6 = mcast_group; - - fail_if(pico_mld_state_change(NULL, &mcast_group, 0, NULL, PICO_MLD_STATE_CREATE) != -1); - /* All host group */ - pico_string_to_ipv6("FF01:0:0:0:0:0:0:1", mcast_group.addr); - fail_if(pico_mld_state_change(&mcast_link, &mcast_group, 0, NULL, PICO_MLD_STATE_CREATE) != 0); - pico_string_to_ipv6("AAAA::107", mcast_group.addr); - fail_if(pico_mld_state_change(&mcast_link, &mcast_group, 0, NULL, 99) != -1); - pico_tree_insert(&MLDParameters, &p); - fail_if(pico_mld_state_change(&mcast_link, &mcast_group, 0, NULL, 99) != -1); - pico_tree_delete(&MLDParameters, &p); -} -END_TEST -START_TEST(tc_pico_mld_analyse_packet) -{ - struct pico_frame *f; - struct pico_device *dev = pico_null_create("dummy0"); - struct pico_ip6 addr; - struct pico_ip6 local; - struct pico_ipv6_hdr *ip6; - struct pico_ipv6_hbhoption *hbh; - struct pico_icmp6_hdr *mld; - f = pico_proto_ipv6.alloc(&pico_proto_ipv6, dev, sizeof(struct mld_message) + MLD_ROUTER_ALERT_LEN); - pico_string_to_ipv6("AAAA::108", addr.addr); - pico_string_to_ipv6("FE80::1", local.addr); - /* No link */ - fail_if(pico_mld_analyse_packet(f) != NULL); - pico_ipv6_link_add(dev, addr, addr); - ip6 = (struct pico_ipv6_hdr *) f->net_hdr; - ip6->hop = 99; - /* Incorrect hop */ - fail_if(pico_mld_analyse_packet(f) != NULL); - ip6->hop = 1; - hbh = (struct pico_ipv6_hbhoption *) f->transport_hdr; - pico_mld_fill_hopbyhop(hbh); - hbh->type = 99; - /* incorrect hop by hop */ - fail_if(pico_mld_analyse_packet(f) != NULL); - pico_mld_fill_hopbyhop(hbh); - ip6->src = addr; - /* Not link local */ - fail_if(pico_mld_analyse_packet(f) != NULL); - memcpy(&ip6->src, PICO_IP6_ANY, sizeof(struct pico_ip6)); - fail_if(pico_mld_analyse_packet(f) != NULL); - ip6->src = local; - mld = (struct pico_icmp6_hdr *) (f->transport_hdr + MLD_ROUTER_ALERT_LEN); - mld->type = 0; - - /* wrong type */ - fail_if(pico_mld_analyse_packet(f) != NULL); - /* all correct */ - mld->type = PICO_MLD_QUERY; - fail_if(pico_mld_analyse_packet(f) == NULL); - mld->type = PICO_MLD_REPORT; - fail_if(pico_mld_analyse_packet(f) == NULL); - mld->type = PICO_MLD_DONE; - fail_if(pico_mld_analyse_packet(f) == NULL); - mld->type = PICO_MLD_REPORTV2; - fail_if(pico_mld_analyse_packet(f) == NULL); -} -END_TEST -START_TEST(tc_pico_mld_discard) -{ - mld_discard(NULL); -} -END_TEST -Suite *pico_suite(void) -{ - - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_mld_fill_hopbyhop = tcase_create("Unit test for pico_mld_fill_hopbyhop"); - TCase *TCase_pico_mld_check_hopbyhop = tcase_create("Unit test for pico_mld_check_hopbyhop"); - TCase *TCase_pico_mld_report_expired = tcase_create("Unit test for pico_mld_report_expired"); - TCase *TCase_mldt_type_compare = tcase_create("Unit test for mldt_type_compare"); - TCase *TCase_pico_mld_analyse_packet = tcase_create("Unit test for pico_mld_analyse_packet"); - TCase *TCase_pico_mld_discard = tcase_create("Unit test for pico_mld_discard"); - TCase *TCase_pico_mld_compatibility_mode = tcase_create("Unit test for pico_mld_compatibility"); - TCase *TCase_pico_mld_v1querier_expired = tcase_create("Unit test for pico_mld_v1querier_expired"); - TCase *TCase_pico_mld_delete_parameter = tcase_create("Unit test for pico_mld_delete_parameter"); - TCase *TCase_pico_mld_timer_expired = tcase_create("Unit test for pico_mld_timer_expired"); - TCase *TCase_pico_mld_timer_reset = tcase_create("Unit test for pico_mld_timer_reset"); - TCase *TCase_pico_mld_send_done = tcase_create("Unit test for pico_mld_send_done"); - TCase *TCase_pico_mld_is_checksum_valid = tcase_create("Unit test for pico_mld_is_checksum"); - TCase *TCase_pico_mld_find_parameter = tcase_create("Unit test for pico_mld_find_parameter"); - TCase *TCase_pico_mld_state_change = tcase_create("Unit test for pico_mld_state_change"); - TCase *TCase_mld_srst = tcase_create("Unit test for pico_mld_srst"); - TCase *TCase_mld_stcl = tcase_create("Unit test for pico_mld_stcl"); - TCase *TCase_pico_mld_process_in = tcase_create("Unit test for pico_mld_process_in"); - TCase *TCase_pico_mld_send_report = tcase_create("Unit test for pico_mld_send_report"); - TCase *TCase_mld_stsdifs = tcase_create("Unit test for mld_stsdifs"); - TCase *TCase_mld_srsf = tcase_create("Unit test for mld_srsf"); - TCase *TCase_mld_rtimrtct = tcase_create("Unit test for mld_rtimrtct"); - TCase *TCase_mld_mrsrrt = tcase_create("Unit test for mld_mrsrrt"); - - tcase_add_test(TCase_pico_mld_fill_hopbyhop, tc_pico_mld_fill_hopbyhop); - suite_add_tcase(s, TCase_pico_mld_fill_hopbyhop); - tcase_add_test(TCase_pico_mld_check_hopbyhop, tc_pico_mld_check_hopbyhop); - suite_add_tcase(s, TCase_pico_mld_check_hopbyhop); - tcase_add_test(TCase_pico_mld_report_expired, tc_pico_mld_report_expired); - suite_add_tcase(s, TCase_pico_mld_report_expired); - tcase_add_test(TCase_mldt_type_compare, tc_mldt_type_compare); - suite_add_tcase(s, TCase_mldt_type_compare); - tcase_add_test(TCase_pico_mld_analyse_packet, tc_pico_mld_analyse_packet); - suite_add_tcase(s, TCase_pico_mld_analyse_packet); - tcase_add_test(TCase_pico_mld_discard, tc_pico_mld_discard); - suite_add_tcase(s, TCase_pico_mld_discard); - tcase_add_test(TCase_pico_mld_compatibility_mode, tc_pico_mld_compatibility_mode); - suite_add_tcase(s, TCase_pico_mld_compatibility_mode); - tcase_add_test(TCase_pico_mld_v1querier_expired, tc_pico_mld_v1querier_expired); - suite_add_tcase(s, TCase_pico_mld_v1querier_expired); - tcase_add_test(TCase_pico_mld_delete_parameter, tc_pico_mld_delete_parameter); - suite_add_tcase(s, TCase_pico_mld_delete_parameter); - tcase_add_test(TCase_pico_mld_timer_expired, tc_pico_mld_timer_expired); - suite_add_tcase(s, TCase_pico_mld_timer_expired); - tcase_add_test(TCase_pico_mld_timer_reset, tc_pico_mld_timer_reset); - suite_add_tcase(s, TCase_pico_mld_timer_reset); - tcase_add_test(TCase_pico_mld_send_done, tc_pico_mld_send_done); - suite_add_tcase(s, TCase_pico_mld_send_done); - tcase_add_test(TCase_pico_mld_is_checksum_valid, tc_pico_mld_is_checksum_valid); - suite_add_tcase(s, TCase_pico_mld_is_checksum_valid); - tcase_add_test(TCase_pico_mld_find_parameter, tc_pico_mld_find_parameter); - suite_add_tcase(s, TCase_pico_mld_find_parameter); - tcase_add_test(TCase_pico_mld_state_change, tc_pico_mld_state_change); - suite_add_tcase(s, TCase_pico_mld_state_change); - tcase_add_test(TCase_mld_srst, tc_mld_srst); - suite_add_tcase(s, TCase_mld_srst); - tcase_add_test(TCase_mld_stcl, tc_mld_stcl); - suite_add_tcase(s, TCase_mld_stcl); - tcase_add_test(TCase_pico_mld_process_in, tc_pico_mld_process_in); - suite_add_tcase(s, TCase_pico_mld_process_in); - tcase_add_test(TCase_pico_mld_send_report, tc_pico_mld_send_report); - suite_add_tcase(s, TCase_pico_mld_send_report); - tcase_add_test(TCase_mld_stsdifs, tc_mld_stsdifs); - suite_add_tcase(s, TCase_mld_stsdifs); - tcase_add_test(TCase_mld_srsf, tc_mld_srsf); - suite_add_tcase(s, TCase_mld_srsf); - tcase_add_test(TCase_mld_rtimrtct, tc_mld_rtimrtct); - suite_add_tcase(s, TCase_mld_rtimrtct); - tcase_add_test(TCase_mld_mrsrrt, tc_mld_mrsrrt); - suite_add_tcase(s, TCase_mld_mrsrrt); - return s; -} -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_protocol.c b/ext/picotcp/test/unit/modunit_pico_protocol.c deleted file mode 100644 index fee1861..0000000 --- a/ext/picotcp/test/unit/modunit_pico_protocol.c +++ /dev/null @@ -1,229 +0,0 @@ -#include "pico_protocol.h" -#include "pico_tree.h" -#include "stack/pico_protocol.c" -#include "check.h" - -Suite *pico_suite(void); - -volatile pico_err_t pico_err = 0; - -static int protocol_passby = 0; - -static struct pico_frame f = { - .next = NULL -}; - -static struct pico_queue q = { - 0 -}; - -static struct pico_tree_node NODE_IN = { - 0 -}; -static struct pico_tree_node NODE_OUT = { - 0 -}; - -#define KEY_IN 0x0D01 -#define KEY_OUT 0x0D00 - - -START_TEST(tc_pico_proto_cmp) -{ - struct pico_protocol a = { - .hash = 0 - }; - struct pico_protocol b = { - .hash = 1 - }; - fail_if(pico_proto_cmp(&a, &b) >= 0); - a.hash = 1; - fail_if(pico_proto_cmp(&a, &b) != 0); - a.hash = 2; - fail_if(pico_proto_cmp(&a, &b) <= 0); -} -END_TEST - -static int modunit_proto_loop_cb_in(struct pico_protocol *self, struct pico_frame *p) -{ - if (!p) - protocol_passby = -1; /* Error! */ - - if (!self) - protocol_passby = -1; /* Error! */ - - if (protocol_passby != 0) /* Ensure that we are called only once. */ - protocol_passby = -1; - - protocol_passby = KEY_IN; - - return 1; /* One frame processed! */ -} - -static int modunit_proto_loop_cb_out(struct pico_protocol *self, struct pico_frame *p) -{ - if (!p) - protocol_passby = -1; /* Error! */ - - if (!self) - protocol_passby = -1; /* Error! */ - - if (protocol_passby != 0) /* Ensure that we are called only once. */ - protocol_passby = -1; - - protocol_passby = KEY_OUT; - - return 1; /* One frame processed! */ -} - -START_TEST(tc_proto_loop_in) -{ - struct pico_protocol p = { - .process_in = modunit_proto_loop_cb_in, .q_in = &q - }; - protocol_passby = 0; - pico_enqueue(p.q_in, &f); - fail_if(proto_loop_in(&p, 1) != 0); - fail_if(protocol_passby != KEY_IN); - - /* Try to dequeue from empty queue, get same loop_score */ - protocol_passby = 0; - fail_if(proto_loop_in(&p, 1) != 1); - fail_if(protocol_passby != 0); -} -END_TEST - - -START_TEST(tc_proto_loop_out) -{ - struct pico_protocol p = { - .process_out = modunit_proto_loop_cb_out, .q_out = &q - }; - protocol_passby = 0; - pico_enqueue(p.q_out, &f); - fail_if(proto_loop_out(&p, 1) != 0); - fail_if(protocol_passby != KEY_OUT); - - /* Try to dequeue from empty queue, get same loop_score */ - protocol_passby = 0; - fail_if(proto_loop_out(&p, 1) != 1); - fail_if(protocol_passby != 0); -} -END_TEST - -START_TEST(tc_proto_loop) -{ - struct pico_protocol p = { - .process_in = modunit_proto_loop_cb_in, - .process_out = modunit_proto_loop_cb_out, - .q_in = &q, - .q_out = &q - }; - protocol_passby = 0; - pico_enqueue(p.q_in, &f); - fail_if(proto_loop(&p, 1, PICO_LOOP_DIR_IN) != 0); - fail_if(protocol_passby != KEY_IN); - - protocol_passby = 0; - pico_enqueue(p.q_out, &f); - fail_if(proto_loop(&p, 1, PICO_LOOP_DIR_OUT) != 0); - fail_if(protocol_passby != KEY_OUT); - -} -END_TEST - -START_TEST(tc_pico_tree_node) -{ - struct pico_proto_rr rr = { - 0 - }; - rr.node_in = &NODE_IN; - rr.node_out = &NODE_OUT; - fail_unless(roundrobin_init(&rr, PICO_LOOP_DIR_IN) == &NODE_IN); - fail_unless(roundrobin_init(&rr, PICO_LOOP_DIR_OUT) == &NODE_OUT); -} -END_TEST - -START_TEST(tc_roundrobin_end) -{ - struct pico_proto_rr rr; - roundrobin_end(&rr, PICO_LOOP_DIR_IN, &NODE_IN); - fail_if(rr.node_in != &NODE_IN); - roundrobin_end(&rr, PICO_LOOP_DIR_OUT, &NODE_OUT); - fail_if(rr.node_out != &NODE_OUT); -} -END_TEST - -START_TEST(tc_pico_protocol_generic_loop) -{ - struct pico_proto_rr rr = { - 0 - }; - int ret = 0; - - rr.node_in = &NODE_IN; - rr.node_out = &NODE_OUT; - ret = pico_protocol_generic_loop(&rr, 0, PICO_LOOP_DIR_IN); - - fail_if(ret != 0); - - pico_protocols_loop(0); -} -END_TEST - - -START_TEST(tc_proto_layer_rr_reset) -{ - struct pico_proto_rr rr; - rr.node_in = &NODE_IN; - rr.node_out = &NODE_OUT; - proto_layer_rr_reset(&rr); - fail_if(rr.node_in != NULL); - fail_if(rr.node_out != NULL); -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("pico_protocol.c"); - - TCase *TCase_pico_proto_cmp = tcase_create("Unit test for pico_proto_cmp"); - TCase *TCase_proto_loop_in = tcase_create("Unit test for proto_loop_in"); - TCase *TCase_proto_loop_out = tcase_create("Unit test for proto_loop_out"); - TCase *TCase_proto_loop = tcase_create("Unit test for proto_loop"); - TCase *TCase_pico_tree_node = tcase_create("Unit test for pico_tree_node"); - TCase *TCase_roundrobin_end = tcase_create("Unit test for roundrobin_end"); - TCase *TCase_pico_protocol_generic_loop = tcase_create("Unit test for pico_protocol_generic_loop"); - TCase *TCase_proto_layer_rr_reset = tcase_create("Unit test for proto_layer_rr_reset"); - - - tcase_add_test(TCase_pico_proto_cmp, tc_pico_proto_cmp); - suite_add_tcase(s, TCase_pico_proto_cmp); - tcase_add_test(TCase_proto_loop_in, tc_proto_loop_in); - suite_add_tcase(s, TCase_proto_loop_in); - tcase_add_test(TCase_proto_loop_out, tc_proto_loop_out); - suite_add_tcase(s, TCase_proto_loop_out); - tcase_add_test(TCase_proto_loop, tc_proto_loop); - suite_add_tcase(s, TCase_proto_loop); - tcase_add_test(TCase_pico_tree_node, tc_pico_tree_node); - suite_add_tcase(s, TCase_pico_tree_node); - tcase_add_test(TCase_roundrobin_end, tc_roundrobin_end); - suite_add_tcase(s, TCase_roundrobin_end); - tcase_add_test(TCase_pico_protocol_generic_loop, tc_pico_protocol_generic_loop); - suite_add_tcase(s, TCase_pico_protocol_generic_loop); - tcase_add_test(TCase_proto_layer_rr_reset, tc_proto_layer_rr_reset); - suite_add_tcase(s, TCase_proto_layer_rr_reset); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_sntp_client.c b/ext/picotcp/test/unit/modunit_pico_sntp_client.c deleted file mode 100644 index b2de620..0000000 --- a/ext/picotcp/test/unit/modunit_pico_sntp_client.c +++ /dev/null @@ -1,428 +0,0 @@ -#include "pico_sntp_client.h" -#include "modules/pico_sntp_client.c" -#include "check.h" -#include "pico_socket.h" -/* Mocking functions, variables, ... */ -volatile pico_time pico_tick = 0ull; -volatile pico_err_t pico_err = 0; - -Suite *pico_suite(void); -void cb_synced(pico_err_t status); - -/* Used in pico_sntp_sync_start */ -struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s)) -{ - struct pico_socket *sock = PICO_ZALLOC(sizeof(struct pico_socket)); - (void) net; - (void) proto; - (void) wakeup; - fail_unless (sock != NULL); - return sock; -} - -/* Used in pico_sntp_sync_start */ -int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port) -{ - (void) s; - (void) local_addr; - (void) port; - return 0; -} - -/* Used in pico_sntp_sync_start */ -int pico_socket_close(struct pico_socket *s) -{ - (void) s; - return 0; -} - -/* Used in pico_sntp_send */ -int8_t pico_socket_del(struct pico_socket *s) -{ - (void) s; - return 0; -} - -/* Used in dnsCallback */ -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) -{ - (void) ipstr; - (void) ip; - return 0; -} - -/* Used in dnsCallback */ -int pico_string_to_ipv6(const char *ipstr, uint8_t *ip) -{ - (void) ipstr; - (void) ip; - return 0; -} - -/* Used in pico_sntp_sync_start_ipv4 */ -int pico_ipv4_to_string(char* ipbuf, const uint32_t ip) -{ - (void) ipbuf; - (void) ip; - return 0; -} - -/* Used in pico_sntp_sync_start_ipv6 */ -int pico_ipv6_to_string(char* ipbuf, const uint8_t ip[PICO_SIZE_IP6]) -{ - (void) ipbuf; - (void) ip; - return 0; -} - -/* Used in pico_sntp_client_wakeup */ -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port) -{ - (void) s; - (void) buf; - (void) len; - (void) orig; - (void) remote_port; - return 0; -} - -/* Used in pico_sntp_send */ -int pico_socket_sendto(struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port) -{ - (void) s; - (void) buf; - (void) len; - (void) dst; - (void) remote_port; - return 0; -} - -/* Used in pico_sntp_sync_start_dns_ipv4, not tested */ -int pico_dns_client_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg) -{ - (void) url; - (void) callback; - (void) arg; - return 0; -} - -/* Used in pico_sntp_sync_start_dns_ipv6, not tested */ -int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg) -{ - (void) url; - (void) callback; - (void) arg; - return 0; -} - -/* Used in pico_sntp_parse */ -void cb_synced(pico_err_t status) -{ - (void) status; - -} - -/* Used in pico_sntp_send */ -static uint32_t timers_added = 0; -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - (void) expire; - (void) timer; - (void) arg; - return ++timers_added; -} - -/* Used in pico_sntp_cleanup */ -void pico_timer_cancel(uint32_t t) -{ - IGNORE_PARAMETER(t); -} - -START_TEST(tc_timestamp_convert) -{ - struct pico_sntp_ts ts; - struct pico_timeval tv; - pico_time delay = 0ull; - int ret = 0; - - /* Input is all zero */ - ts.sec = long_be(0ul); - ts.frac = long_be(0ul); - ret = timestamp_convert(&ts, &tv, delay); - ck_assert(ret == -1); - ck_assert(tv.tv_sec == 0); - ck_assert(tv.tv_msec == 0); - - /* Minimum input*/ - ts.sec = long_be(SNTP_UNIX_OFFSET + 1390000000ul); - ts.frac = long_be(4310344ul); /* MIN value: 1msec */ - ret = timestamp_convert(&ts, &tv, delay); - ck_assert(ret == 0); - fail_unless(tv.tv_sec == 1390000000); - fail_unless(tv.tv_msec == 1); - - /* Intermediate input */ - ts.sec = long_be(SNTP_UNIX_OFFSET + 1390000000ul); - ts.frac = long_be(3865470566ul); /* value: 899msec */ - ret = timestamp_convert(&ts, &tv, delay); - ck_assert(ret == 0); - fail_unless(tv.tv_sec == 1390000000); - fail_unless(tv.tv_msec == 900); - - /* Maximum input */ - ts.sec = long_be(SNTP_UNIX_OFFSET + 1390000000ul); - ts.frac = long_be(4294967295ul); /* MAX value: 999msec */ - ret = timestamp_convert(&ts, &tv, delay); - ck_assert(ret == 0); - fail_unless(tv.tv_sec == 1390000001); - fail_unless(tv.tv_msec == 0); - - /* Intermediate input with delay */ - ts.sec = long_be(SNTP_UNIX_OFFSET + 1390000000ul); - ts.frac = long_be(3865470566ul); /* value: 899msec */ - delay = 200ull; - ret = timestamp_convert(&ts, &tv, delay); - ck_assert(ret == 0); - fail_unless(tv.tv_sec == 1390000001); - fail_unless(tv.tv_msec == 100); -} -END_TEST -START_TEST(tc_pico_sntp_cleanup) -{ - struct sntp_server_ns_cookie *ck; - struct pico_socket *sock; - ck = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - fail_unless (ck != NULL); - ck->hostname = PICO_ZALLOC(sizeof(char) * 5); - fail_unless (ck->hostname != NULL); - ck->stamp = 0ull; - ck->cb_synced = cb_synced; - - sock = pico_socket_open(0, 0, &pico_sntp_client_wakeup); - ck->sock = sock; - sock->priv = ck; - - - pico_sntp_cleanup(ck, PICO_ERR_NOERR); -} -END_TEST -START_TEST(tc_pico_sntp_parse) -{ - /* TODO: test this: static void pico_sntp_parse(char *buf, struct sntp_server_ns_cookie *ck) */ - struct sntp_server_ns_cookie *ck; - struct pico_socket *sock; - struct pico_sntp_header header = { - 0 - }; - - ck = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - fail_unless (ck != NULL); - ck->hostname = PICO_ZALLOC(sizeof(char) * 5); - fail_unless (ck->hostname != NULL); - ck->stamp = 0ull; - ck->cb_synced = cb_synced; - - sock = pico_socket_open(0, 0, &pico_sntp_client_wakeup); - ck->sock = sock; - sock->priv = ck; - - header.mode = 4; /* server mode */ - header.vn = 4; /* sntp version 4 */ - header.stratum = 1; /* primary reference */ - header.trs_ts.sec = long_be(SNTP_UNIX_OFFSET + 1390000000ul); - header.trs_ts.frac = long_be(3865470566ul); /* value: 899msec */ - - fail_if(pico_sntp_parse((char *) &header, NULL) == 0); - fail_if(pico_sntp_parse((char *) &header, ck) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_client_wakeup) -{ - /* TODO: test this: static void pico_sntp_client_wakeup(uint16_t ev, struct pico_socket *s) */ - uint16_t event = PICO_SOCK_EV_ERR; - struct sntp_server_ns_cookie *ck; - struct pico_socket *sock; - ck = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - fail_unless (ck != NULL); - ck->hostname = PICO_ZALLOC(sizeof(char) * 5); - fail_unless (ck->hostname != NULL); - ck->stamp = 0ull; - ck->cb_synced = cb_synced; - - sock = pico_socket_open(0, 0, &pico_sntp_client_wakeup); - ck->sock = sock; - sock->priv = ck; - - ck->cb_synced = cb_synced; - printf("Started wakeup unit test\n"); - - pico_sntp_client_wakeup(event, sock); -} -END_TEST -START_TEST(tc_sntp_receive_timeout) -{ - struct sntp_server_ns_cookie *ck; - struct pico_socket *sock; - ck = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - fail_unless (ck != NULL); - ck->hostname = PICO_ZALLOC(sizeof(char) * 5); - fail_unless (ck->hostname != NULL); - ck->stamp = 0ull; - ck->cb_synced = cb_synced; - - sock = pico_socket_open(0, 0, &pico_sntp_client_wakeup); - ck->sock = sock; - sock->priv = ck; - sntp_receive_timeout(0ull, ck); - -} -END_TEST -START_TEST(tc_pico_sntp_send) -{ - /* TODO: test this: static void pico_sntp_send(struct pico_socket *sock, union pico_address *dst) */ - struct pico_socket sock = { - 0 - }; - union pico_address dst; - struct sntp_server_ns_cookie ck = { - 0 - }; - sock.priv = &ck; - - pico_sntp_send(&sock, &dst); -} -END_TEST -START_TEST(tc_dnsCallback) -{ - /* TODO: test this: static void dnsCallback(char *ip, void *arg) */ - char ip[] = "198.123.30.132"; - struct sntp_server_ns_cookie *ck; - ck = PICO_ZALLOC(sizeof(struct sntp_server_ns_cookie)); - - dnsCallback(ip, ck); -} -END_TEST -START_TEST(tc_pico_sntp_sync) -{ - const char *sntp_server= "ntp.nasa.gov"; - - fail_if(pico_sntp_sync(NULL, cb_synced) == 0); - fail_if(pico_err != PICO_ERR_EINVAL); - - fail_if(pico_sntp_sync(sntp_server, NULL) == 0); - fail_if(pico_err != PICO_ERR_EINVAL); - - fail_if(pico_sntp_sync(sntp_server, cb_synced) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_sync_ip) -{ - union pico_address sntp_addr = { .ip4.addr = 0ul }; - - fail_if(pico_sntp_sync_ip(NULL, cb_synced) == 0); - fail_if(pico_err != PICO_ERR_EINVAL); - - fail_if(pico_sntp_sync_ip(&sntp_addr, NULL) == 0); - fail_if(pico_err != PICO_ERR_EINVAL); - - fail_if(pico_sntp_sync_ip(&sntp_addr, cb_synced) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_sync_start) -{ - struct sntp_server_ns_cookie ck = { 0 }; - union pico_address sntp_addr = { .ip4.addr= 0ul }; - - fail_if(pico_sntp_sync_start(&ck, &sntp_addr) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_sync_start_dns_ipv4) -{ - const char *sntp_server = "ntp.nasa.gov"; - - fail_if(pico_sntp_sync_start_dns_ipv4(sntp_server, cb_synced) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_sync_start_dns_ipv6) -{ - const char *sntp_server = "ntp.nasa.gov"; - - fail_if(pico_sntp_sync_start_dns_ipv6(sntp_server, cb_synced) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_sync_start_ipv4) -{ - union pico_address sntp_addr = { .ip4.addr = 0}; - - fail_if(pico_sntp_sync_start_ipv4(&sntp_addr, cb_synced) != 0); -} -END_TEST -START_TEST(tc_pico_sntp_sync_start_ipv6) -{ - union pico_address sntp_addr = { .ip6.addr = { 0 } }; - - fail_if(pico_sntp_sync_start_ipv6(&sntp_addr, cb_synced) != 0); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_timestamp_convert = tcase_create("Unit test for pico_timeval"); - TCase *TCase_pico_sntp_cleanup = tcase_create("Unit test for pico_sntp_cleanup"); - TCase *TCase_pico_sntp_send = tcase_create("Unit test for pico_sntp_send"); - TCase *TCase_pico_sntp_parse = tcase_create("Unit test for pico_sntp_parse"); - TCase *TCase_pico_sntp_client_wakeup = tcase_create("Unit test for pico_sntp_client_wakeup"); - TCase *TCase_sntp_receive_timeout = tcase_create("Unit test for sntp_receive_timeout"); - TCase *TCase_dnsCallback = tcase_create("Unit test for dnsCallback"); - TCase *TCase_pico_sntp_sync = tcase_create("Unit test for pico_sntp_sync"); - TCase *TCase_pico_sntp_sync_ip = tcase_create("Unit test for pico_sntp_sync_ip"); - TCase *TCase_pico_sntp_sync_start = tcase_create("Unit test for pico_sntp_sync_start"); - TCase *TCase_pico_sntp_sync_start_dns_ipv4 = tcase_create("Unit test for pico_sntp_sync_start_dns_ipv4"); - TCase *TCase_pico_sntp_sync_start_dns_ipv6 = tcase_create("Unit test for pico_sntp_sync_start_dns_ipv6"); - TCase *TCase_pico_sntp_sync_start_ipv4 = tcase_create("Unit test for pico_sntp_sync_start_ipv4"); - TCase *TCase_pico_sntp_sync_start_ipv6 = tcase_create("Unit test for pico_sntp_sync_start_ipv6"); - - - tcase_add_test(TCase_timestamp_convert, tc_timestamp_convert); - suite_add_tcase(s, TCase_timestamp_convert); - tcase_add_test(TCase_pico_sntp_cleanup, tc_pico_sntp_cleanup); - suite_add_tcase(s, TCase_pico_sntp_cleanup); - tcase_add_test(TCase_pico_sntp_parse, tc_pico_sntp_parse); - suite_add_tcase(s, TCase_pico_sntp_parse); - tcase_add_test(TCase_pico_sntp_client_wakeup, tc_pico_sntp_client_wakeup); - suite_add_tcase(s, TCase_pico_sntp_client_wakeup); - tcase_add_test(TCase_sntp_receive_timeout, tc_sntp_receive_timeout); - suite_add_tcase(s, TCase_sntp_receive_timeout); - tcase_add_test(TCase_pico_sntp_send, tc_pico_sntp_send); - suite_add_tcase(s, TCase_pico_sntp_send); - tcase_add_test(TCase_dnsCallback, tc_dnsCallback); - suite_add_tcase(s, TCase_dnsCallback); - tcase_add_test(TCase_pico_sntp_sync, tc_pico_sntp_sync); - suite_add_tcase(s, TCase_pico_sntp_sync); - tcase_add_test(TCase_pico_sntp_sync_ip, tc_pico_sntp_sync_ip); - suite_add_tcase(s, TCase_pico_sntp_sync_ip); - tcase_add_test(TCase_pico_sntp_sync_start, tc_pico_sntp_sync_start); - suite_add_tcase(s, TCase_pico_sntp_sync_start); - tcase_add_test(TCase_pico_sntp_sync_start_dns_ipv4, tc_pico_sntp_sync_start_dns_ipv4); - suite_add_tcase(s, TCase_pico_sntp_sync_start_dns_ipv4); - tcase_add_test(TCase_pico_sntp_sync_start_dns_ipv6, tc_pico_sntp_sync_start_dns_ipv6); - suite_add_tcase(s, TCase_pico_sntp_sync_start_dns_ipv6); - tcase_add_test(TCase_pico_sntp_sync_start_ipv4, tc_pico_sntp_sync_start_ipv4); - suite_add_tcase(s, TCase_pico_sntp_sync_start_ipv4); - tcase_add_test(TCase_pico_sntp_sync_start_ipv6, tc_pico_sntp_sync_start_ipv6); - suite_add_tcase(s, TCase_pico_sntp_sync_start_ipv6); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_stack.c b/ext/picotcp/test/unit/modunit_pico_stack.c deleted file mode 100644 index bc51638..0000000 --- a/ext/picotcp/test/unit/modunit_pico_stack.c +++ /dev/null @@ -1,145 +0,0 @@ -#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_eth.h" -#include "pico_arp.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_icmp4.h" -#include "pico_igmp.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "heap.h" -#include "stack/pico_stack.c" -#include "check.h" - - -Suite *pico_suite(void); -void fake_timer(pico_time __attribute__((unused)) now, void __attribute__((unused)) *n); - -START_TEST(tc_pico_ll_receive) -{ - /* TODO: test this: static int32_t pico_ll_receive(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_ll_check_bcast) -{ - /* TODO: test this: static void pico_ll_check_bcast(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_destination_is_bcast) -{ - /* TODO: test this: static int destination_is_bcast(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_destination_is_mcast) -{ - /* TODO: test this: static int destination_is_mcast(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_eth) -{ - /* TODO: test this: static struct pico_eth *pico_ethernet_mcast_translate(struct pico_frame *f, uint8_t *pico_mcast_mac) */ -} -END_TEST -START_TEST(tc_pico_ethsend_local) -{ - /* TODO: test this: static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr, int *ret) */ -} -END_TEST -START_TEST(tc_pico_ethsend_bcast) -{ - /* TODO: test this: static int32_t pico_ethsend_bcast(struct pico_frame *f, int *ret) */ -} -END_TEST -START_TEST(tc_pico_ethsend_dispatch) -{ - /* TODO: test this: static int32_t pico_ethsend_dispatch(struct pico_frame *f, int *ret) */ -} -END_TEST -START_TEST(tc_calc_score) -{ - /* TODO: test this: static int calc_score(int *score, int *index, int avg[][PROTO_DEF_AVG_NR], int *ret) */ -} -END_TEST - -#ifdef PICO_FAULTY -void fake_timer(pico_time __attribute__((unused)) now, void __attribute__((unused)) *n) -{ - -} -#endif - -START_TEST(tc_stack_generic) -{ -#ifdef PICO_FAULTY - printf("Testing with faulty memory in pico_stack_init (11)\n"); - pico_set_mm_failure(13); - fail_if(pico_stack_init() != -1); -#endif - pico_stack_init(); -#ifdef PICO_FAULTY - printf("Testing with faulty memory in pico_timer_add (1)\n"); - pico_set_mm_failure(1); - fail_if(pico_timer_add(0, fake_timer, NULL) != 0); -#endif - - -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_pico_ll_receive = tcase_create("Unit test for pico_ll_receive"); - TCase *TCase_pico_ll_check_bcast = tcase_create("Unit test for pico_ll_check_bcast"); - TCase *TCase_destination_is_bcast = tcase_create("Unit test for destination_is_bcast"); - TCase *TCase_destination_is_mcast = tcase_create("Unit test for destination_is_mcast"); - TCase *TCase_pico_eth = tcase_create("Unit test for pico_eth"); - TCase *TCase_pico_ethsend_local = tcase_create("Unit test for pico_ethsend_local"); - TCase *TCase_pico_ethsend_bcast = tcase_create("Unit test for pico_ethsend_bcast"); - TCase *TCase_pico_ethsend_dispatch = tcase_create("Unit test for pico_ethsend_dispatch"); - TCase *TCase_calc_score = tcase_create("Unit test for calc_score"); - TCase *TCase_stack_generic = tcase_create("GENERIC stack initialization unit test"); - - - tcase_add_test(TCase_pico_ll_receive, tc_pico_ll_receive); - suite_add_tcase(s, TCase_pico_ll_receive); - tcase_add_test(TCase_pico_ll_check_bcast, tc_pico_ll_check_bcast); - suite_add_tcase(s, TCase_pico_ll_check_bcast); - tcase_add_test(TCase_destination_is_bcast, tc_destination_is_bcast); - suite_add_tcase(s, TCase_destination_is_bcast); - tcase_add_test(TCase_destination_is_mcast, tc_destination_is_mcast); - suite_add_tcase(s, TCase_destination_is_mcast); - tcase_add_test(TCase_pico_eth, tc_pico_eth); - suite_add_tcase(s, TCase_pico_eth); - tcase_add_test(TCase_pico_ethsend_local, tc_pico_ethsend_local); - suite_add_tcase(s, TCase_pico_ethsend_local); - tcase_add_test(TCase_pico_ethsend_bcast, tc_pico_ethsend_bcast); - suite_add_tcase(s, TCase_pico_ethsend_bcast); - tcase_add_test(TCase_pico_ethsend_dispatch, tc_pico_ethsend_dispatch); - suite_add_tcase(s, TCase_pico_ethsend_dispatch); - tcase_add_test(TCase_calc_score, tc_calc_score); - suite_add_tcase(s, TCase_calc_score); - tcase_add_test(TCase_stack_generic, tc_stack_generic); - suite_add_tcase(s, TCase_stack_generic); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_strings.c b/ext/picotcp/test/unit/modunit_pico_strings.c deleted file mode 100644 index b0d5104..0000000 --- a/ext/picotcp/test/unit/modunit_pico_strings.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "modules/pico_strings.c" -#include "check.h" - -Suite *pico_suite(void); - -START_TEST(tc_get_string_terminator_position) -{ - char buf[6] = "unit"; - get_string_terminator_position(NULL,0); - fail_if(get_string_terminator_position(buf,2) != 0); - fail_if(get_string_terminator_position(buf,6) != &buf[4]); -} -END_TEST -START_TEST(tc_pico_strncasecmp) -{ - fail_if(pico_strncasecmp("unit","UNIT",4) != 0); - fail_if(pico_strncasecmp("unit1","UNIT2",5) != -1); - fail_if(pico_strncasecmp("unit2","UNIT1",5) != 1); -} -END_TEST -START_TEST(tc_num2string) -{ - char buf[20]; - fail_if(num2string(-1,NULL,1) != -1); - fail_if(num2string(1,NULL,1) != -1); - fail_if(num2string(1,buf,1) != -1); - fail_if(num2string(1,buf,3) != 2); - fail_if(num2string(11,buf,3) != 3); - fail_if(num2string(112,buf,4) != 4); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_get_string_terminator_position = tcase_create("Unit test for get_string_terminator_position"); - TCase *TCase_num2string = tcase_create("Unit test for num2string"); - TCase *TCase_pico_strncasecmp = tcase_create("Unit test for pico_strncasecmp"); - - tcase_add_test(TCase_get_string_terminator_position, tc_get_string_terminator_position); - suite_add_tcase(s, TCase_get_string_terminator_position); - tcase_add_test(TCase_num2string,tc_num2string); - suite_add_tcase(s, TCase_num2string); - tcase_add_test(TCase_pico_strncasecmp,tc_pico_strncasecmp); - suite_add_tcase(s, TCase_pico_strncasecmp); - - return s; -} -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_tcp.c b/ext/picotcp/test/unit/modunit_pico_tcp.c deleted file mode 100644 index f2b19ca..0000000 --- a/ext/picotcp/test/unit/modunit_pico_tcp.c +++ /dev/null @@ -1,863 +0,0 @@ -#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" -#include "modules/pico_tcp.c" -#include "check.h" - -Suite *pico_suite(void); - -static uint32_t timers_added = 0; -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - IGNORE_PARAMETER(expire); - IGNORE_PARAMETER(timer); - IGNORE_PARAMETER(arg); - return ++timers_added; -} - -START_TEST(tc_input_segment_compare) -{ - struct tcp_input_segment A = { - .seq = 0xFFFFFFFF - }; - struct tcp_input_segment B = { - .seq = 0xFFFFFFFe - }; - struct tcp_input_segment a = { - .seq = 0x01 - }; - struct tcp_input_segment b = { - .seq = 0x02 - }; - - fail_if(input_segment_compare(&A, &B) <= 0); - fail_if(input_segment_compare(&a, &b) >= 0); - fail_if(input_segment_compare(&A, &b) >= 0); - fail_if(input_segment_compare(&A, &A) != 0); -} -END_TEST -START_TEST(tc_tcp_input_segment) -{ - /* TODO: test this: static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) */ - struct pico_frame *f = pico_frame_alloc(60); - struct tcp_input_segment *seg; - - fail_if(!f); - f->payload = f->start; - f->payload_len = 60; - f->transport_hdr = f->payload; - f->transport_len = (uint16_t)(f->payload_len - 40); - memset(f->payload, 'c', f->payload_len); - ((struct pico_tcp_hdr *)((f)->transport_hdr))->seq = long_be(0xdeadbeef); - - seg = segment_from_frame(f); - fail_if(!seg); - fail_if(seg->seq != 0xdeadbeef); - fail_if(seg->payload_len != f->payload_len); - fail_if(memcmp(seg->payload, f->payload, f->payload_len) != 0); - -#ifdef PICO_FAULTY - printf("Testing with faulty memory in segment_from_frame (1)\n"); - pico_set_mm_failure(1); - seg = segment_from_frame(f); - fail_if(seg); - - printf("Testing with faulty memory in segment_from_frame (2)\n"); - pico_set_mm_failure(2); - seg = segment_from_frame(f); - fail_if(seg); -#endif - printf("Testing segment_from_frame with empty payload\n"); - f->payload_len = 0; - seg = segment_from_frame(f); - fail_if(seg); - -} -END_TEST -START_TEST(tc_segment_compare) -{ - /* TODO: test this: static int segment_compare(void *ka, void *kb) */ - struct pico_frame *a = pico_frame_alloc(40); - struct pico_frame *b = pico_frame_alloc(60); - a->transport_hdr = a->start; - b->transport_hdr = b->start; - - ((struct pico_tcp_hdr *)((b)->transport_hdr))->seq = long_be(0xaa00); - ((struct pico_tcp_hdr *)((a)->transport_hdr))->seq = long_be(0xffffaa00); - fail_if(segment_compare(a, b) >= 0); - fail_if(segment_compare(a, a) != 0); - - -} -END_TEST -START_TEST(tc_tcp_discard_all_segments) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)pico_tcp_open(PICO_PROTO_IPV4); - struct pico_frame *f = pico_frame_alloc(80); - struct tcp_input_segment *is; - fail_if(!t); - fail_if(!f); - - printf("Testing enqueuing bogus frame\n"); - f->buffer_len = 0; - fail_if(pico_enqueue_segment(&t->tcpq_out, f) >= 0); - f->buffer_len = 80; - f->transport_hdr = f->start; - f->transport_len = (uint16_t)(f->buffer_len - 40); - f->payload = f->start + 40; - f->payload_len = 40; - memset(f->payload, 'c', f->payload_len); - is = segment_from_frame(f); - fail_if(!is); - is->payload_len = 0; - fail_if(pico_enqueue_segment(&t->tcpq_in, is) >= 0); - is->payload_len = 40; - - /* Successfull cases */ - fail_if(pico_enqueue_segment(&t->tcpq_out, f) <= 0); - fail_if(pico_enqueue_segment(&t->tcpq_in, is) <= 0); - - /* Fail because size exceeded. Must return 0. */ - t->tcpq_out.max_size = 50; - t->tcpq_in.max_size = 50; - fail_if(pico_enqueue_segment(&t->tcpq_out, f) != 0); - fail_if(pico_enqueue_segment(&t->tcpq_in, is) != 0); - - -#ifdef PICO_FAULTY - /* Fail because the tree cannot allocate a new node. Should return 0 */ - printf("Testing with faulty memory (1)\n"); - pico_set_mm_failure(1); - fail_if(pico_enqueue_segment(&t->tcpq_out, f) > 0); - pico_set_mm_failure(1); - fail_if(pico_enqueue_segment(&t->tcpq_in, is) > 0); - - printf("Testing input segment conversion with faulty mm(1)\n"); - pico_set_mm_failure(1); - is = segment_from_frame(f); - fail_if(is); - printf("Testing input segment conversion with faulty mm(2)\n"); - pico_set_mm_failure(2); - is = segment_from_frame(f); - fail_if(is); -#endif - - /* Discard all segments */ - fail_if(t->tcpq_out.size == 0); - fail_if(t->tcpq_out.frames == 0); - tcp_discard_all_segments(&t->tcpq_out); - fail_if(t->tcpq_out.size != 0); - fail_if(t->tcpq_out.frames != 0); - - fail_if(t->tcpq_in.size == 0); - fail_if(t->tcpq_in.frames == 0); - fail_if(pico_tcp_queue_in_is_empty(&t->sock)); - - tcp_discard_all_segments(&t->tcpq_in); - fail_if(t->tcpq_in.size != 0); - fail_if(t->tcpq_in.frames != 0); - fail_unless(pico_tcp_queue_in_is_empty(&t->sock)); - - - /* Testing next_segment with NULLS */ - fail_if(next_segment(NULL, NULL) != NULL); -} -END_TEST - -START_TEST(tc_release_until) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)pico_tcp_open(PICO_PROTO_IPV6); - struct pico_frame *f; - uint32_t i = 0; - int ret = 0; - struct tcp_input_segment *is; - fail_if(!t); - ret = release_until(&t->tcpq_out, 0); - fail_unless(ret == 0); - - /* Test with output queue */ - for (i = 0; i < 32; i++) { - f = pico_frame_alloc(84); - fail_if(!f); - f->transport_hdr = f->start; - f->transport_len = (uint16_t)f->buffer_len; - f->payload_len = f->transport_len; - ((struct pico_tcp_hdr *)((f)->transport_hdr))->seq = long_be(0xaa00 + f->buffer_len * i); - printf("inserting frame seq = %08x len = %d\n", 0xaa00 + f->buffer_len * i, f->buffer_len); - fail_if(pico_enqueue_segment(&t->tcpq_out, f) <= 0); - } - ret = release_until(&t->tcpq_out, 0xaa00 + f->buffer_len * 30); - printf("Release until %08x\n", 0xaa00 + f->buffer_len * 30); - fail_if(ret != 30); - printf("Ret is %d\n", ret); - printf("Remaining is %d\n", t->tcpq_out.frames); - fail_if(t->tcpq_out.frames != 2); - - /* Test with input queue */ - for (i = 0; i < 32; i++) { - f = pico_frame_alloc(84); - fail_if(!f); - f->transport_hdr = f->start; - f->transport_len = (uint16_t)f->buffer_len; - f->payload_len = f->transport_len; - f->payload = f->start; - ((struct pico_tcp_hdr *)((f)->transport_hdr))->seq = long_be(0xaa00 + f->buffer_len * i); - is = segment_from_frame(f); - fail_if(!is); - printf("inserting Input frame seq = %08x len = %d\n", long_be(is->seq), is->payload_len); - fail_if(!is); - fail_if(pico_enqueue_segment(&t->tcpq_in, is) <= 0); - } - ret = release_until(&t->tcpq_in, 0xaa00 + f->buffer_len * 30); - printf("Release until %08x\n", 0xaa00 + f->buffer_len * 30); - fail_if(ret != 30); - printf("Ret is %d\n", ret); - printf("Remaining is %d\n", t->tcpq_out.frames); - fail_if(t->tcpq_out.frames != 2); -} -END_TEST - -START_TEST(tc_release_all_until) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)pico_tcp_open(PICO_PROTO_IPV4); - struct pico_frame *f; - uint32_t i = 0; - int ret = 0; - struct tcp_input_segment *is; - pico_time tm; - fail_if(!t); - ret = release_all_until(&t->tcpq_out, 0, &tm); - fail_unless(ret == 0); - - /* Test with output queue */ - for (i = 0; i < 32; i++) { - f = pico_frame_alloc(84); - fail_if(!f); - f->transport_hdr = f->start; - f->transport_len = (uint16_t)f->buffer_len; - f->payload_len = f->transport_len; - ((struct pico_tcp_hdr *)((f)->transport_hdr))->seq = long_be(0xaa00 + f->buffer_len * i); - printf("inserting frame seq = %08x len = %d\n", 0xaa00 + f->buffer_len * i, f->buffer_len); - fail_if(pico_enqueue_segment(&t->tcpq_out, f) <= 0); - } - ret = release_all_until(&t->tcpq_out, 0xaa00 + f->buffer_len * 30, &tm); - printf("Release until %08x\n", 0xaa00 + f->buffer_len * 30); - fail_if(ret != 30); - printf("Ret is %d\n", ret); - printf("Remaining is %d\n", t->tcpq_out.frames); - fail_if(t->tcpq_out.frames != 2); - - /* Test with input queue */ - for (i = 0; i < 32; i++) { - f = pico_frame_alloc(84); - fail_if(!f); - f->transport_hdr = f->start; - f->transport_len = (uint16_t)f->buffer_len; - f->payload_len = f->transport_len; - f->payload = f->start; - ((struct pico_tcp_hdr *)((f)->transport_hdr))->seq = long_be(0xaa00 + f->buffer_len * i); - is = segment_from_frame(f); - fail_if(!is); - printf("inserting Input frame seq = %08x len = %d\n", long_be(is->seq), is->payload_len); - fail_if(!is); - fail_if(pico_enqueue_segment(&t->tcpq_in, is) <= 0); - } - ret = release_all_until(&t->tcpq_in, 0xaa00 + f->buffer_len * 30, &tm); - printf("Release until %08x\n", 0xaa00 + f->buffer_len * 30); - fail_if(ret != 30); - printf("Ret is %d\n", ret); - printf("Remaining is %d\n", t->tcpq_out.frames); - fail_if(t->tcpq_out.frames != 2); - - /* Test enqueue_segment with NULL segment */ - fail_if(pico_enqueue_segment(NULL, NULL) != -1); - - -} -END_TEST -START_TEST(tc_tcp_send_fin) -{ - /* TODO: test this: static void tcp_send_fin(struct pico_socket_tcp *t); */ -} -END_TEST -START_TEST(tc_pico_tcp_process_out) -{ - /* TODO: test this: static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_pico_paws) -{ - pico_paws(); - /* Nothing to test for a random function...*/ -} -END_TEST - - -START_TEST(tc_tcp_add_options) -{ - /* TODO: test this: static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz) */ - struct pico_socket_tcp ts = { }; - struct pico_frame *f = pico_frame_alloc(100); - uint16_t flags = 0; - uint16_t optsiz = 50; - uint8_t *frame_opt_buff; - int i; - struct tcp_sack_block *a, *b, *c; - uint32_t al = 0xa0, - ar = 0xaf, - bl = 0xb0, - br = 0xbf, - cl = 0xc0, - cr = 0xcf; - f->transport_hdr = f->start; - f->transport_len = (uint16_t)f->buffer_len; - f->payload_len = f->transport_len; - frame_opt_buff = f->transport_hdr + PICO_SIZE_TCPHDR; - - /* Window scale only */ - printf("Testing window scale option\n"); - ts.wnd_scale = 66; - tcp_add_options(&ts, f, flags, optsiz); - fail_if(frame_opt_buff[0] != PICO_TCP_OPTION_WS); - fail_if(frame_opt_buff[1] != PICO_TCPOPTLEN_WS); - fail_if(frame_opt_buff[2] != 66); - for (i = 3; i < optsiz - 1; i++) - fail_if(frame_opt_buff[i] != PICO_TCP_OPTION_NOOP); - fail_if(frame_opt_buff[optsiz - 1] != PICO_TCP_OPTION_END); - - /* MSS + SACK_OK + WS + TIMESTAMPS */ - printf("Testing full SYN options\n"); - flags = PICO_TCP_SYN; - ts.wnd_scale = 66; - ts.mss = 0xAA88; - tcp_add_options(&ts, f, flags, optsiz); - fail_if(frame_opt_buff[0] != PICO_TCP_OPTION_MSS); - fail_if(frame_opt_buff[1] != PICO_TCPOPTLEN_MSS); - fail_if(frame_opt_buff[2] != 0xAA); - fail_if(frame_opt_buff[3] != 0x88); - fail_if(frame_opt_buff[4] != PICO_TCP_OPTION_SACK_OK); - fail_if(frame_opt_buff[5] != PICO_TCPOPTLEN_SACK_OK); - fail_if(frame_opt_buff[6] != PICO_TCP_OPTION_WS); - fail_if(frame_opt_buff[7] != PICO_TCPOPTLEN_WS); - fail_if(frame_opt_buff[8] != 66); - fail_if(frame_opt_buff[9] != PICO_TCP_OPTION_TIMESTAMP); - fail_if(frame_opt_buff[10] != PICO_TCPOPTLEN_TIMESTAMP); - /* Timestamps: up to byte 18 */ - for (i = 19; i < optsiz - 1; i++) - fail_if(frame_opt_buff[i] != PICO_TCP_OPTION_NOOP); - fail_if(frame_opt_buff[optsiz - 1] != PICO_TCP_OPTION_END); - - /* Testing SACKs */ - printf("Testing full SACK options\n"); - a = PICO_ZALLOC(sizeof (struct tcp_sack_block)); - b = PICO_ZALLOC(sizeof (struct tcp_sack_block)); - c = PICO_ZALLOC(sizeof (struct tcp_sack_block)); - a->left = al; - a->right = ar; - a->next = b; - b->left = bl; - b->right = br; - b->next = c; - c->left = cl; - c->right = cr; - c->next = NULL; - - ts.sack_ok = 1; - ts.sacks = a; - flags = PICO_TCP_ACK; - tcp_add_options(&ts, f, flags, optsiz); - fail_if(frame_opt_buff[0] != PICO_TCP_OPTION_WS); - fail_if(frame_opt_buff[1] != PICO_TCPOPTLEN_WS); - fail_if(frame_opt_buff[2] != 66); - fail_if(frame_opt_buff[3] != PICO_TCP_OPTION_SACK); - fail_if(frame_opt_buff[4] != PICO_TCPOPTLEN_SACK + 6 * (sizeof(uint32_t))); - fail_if(memcmp(frame_opt_buff + 5, &al, 4) != 0); - fail_if(memcmp(frame_opt_buff + 9, &ar, 4) != 0); - fail_if(memcmp(frame_opt_buff + 13, &bl, 4) != 0); - fail_if(memcmp(frame_opt_buff + 17, &br, 4) != 0); - fail_if(memcmp(frame_opt_buff + 21, &cl, 4) != 0); - fail_if(memcmp(frame_opt_buff + 25, &cr, 4) != 0); - fail_if(ts.sacks != NULL); - for (i = 29; i < optsiz - 1; i++) - fail_if(frame_opt_buff[i] != PICO_TCP_OPTION_NOOP); - fail_if(frame_opt_buff[optsiz - 1] != PICO_TCP_OPTION_END); - - - - - - -} -END_TEST -START_TEST(tc_tcp_options_size_frame) -{ - /* TODO: test this: static uint16_t tcp_options_size_frame(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_add_options_frame) -{ - /* TODO: test this: static void tcp_add_options_frame(struct pico_socket_tcp *ts, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_send_ack) -{ - /* TODO: test this: static void tcp_send_ack(struct pico_socket_tcp *t); */ -} -END_TEST -START_TEST(tc_tcp_set_space) -{ - /* TODO: test this: static void tcp_set_space(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_tcp_options_size) -{ - /* TODO: test this: static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags) */ -} -END_TEST -START_TEST(tc_tcp_process_sack) -{ - /* TODO: test this: static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end) */ -} -END_TEST -START_TEST(tc_tcp_rcv_sack) -{ - /* TODO: test this: static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len) */ -} -END_TEST -START_TEST(tc_tcp_parse_options) -{ - /* TODO: test this: static void tcp_parse_options(struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_send) -{ - /* TODO: test this: static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_sock_stats) -{ - /* TODO: test this: static void sock_stats(uint32_t when, void *arg) */ -} -END_TEST -START_TEST(tc_initconn_retry) -{ - /* TODO: test this: static void initconn_retry(pico_time when, void *arg) */ -} -END_TEST -START_TEST(tc_tcp_send_synack) -{ - /* TODO: test this: static int tcp_send_synack(struct pico_socket *s) */ -} -END_TEST -START_TEST(tc_tcp_send_empty) -{ - /* TODO: test this: static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags, int is_keepalive) */ -} -END_TEST -START_TEST(tc_tcp_send_probe) -{ - /* TODO: test this: static void tcp_send_probe(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_tcp_send_rst) -{ - /* TODO: test this: static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr) */ -} -END_TEST -START_TEST(tc_tcp_nosync_rst) -{ - /* TODO: test this: static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr) */ -} -END_TEST -START_TEST(tc_tcp_sack_prepare) -{ - /* TODO: test this: static void tcp_sack_prepare(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_tcp_data_in) -{ - /* TODO: test this: static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_ack_advance_una) -{ - /* TODO: test this: static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, pico_time *timestamp) */ -} -END_TEST -START_TEST(tc_time_diff) -{ - /* TODO: test this: static uint16_t time_diff(pico_time a, pico_time b) */ -} -END_TEST -START_TEST(tc_tcp_rtt) -{ - /* TODO: test this: static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt) */ - -} -END_TEST -START_TEST(tc_tcp_congestion_control) -{ - /* TODO: test this: static void tcp_congestion_control(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_add_retransmission_timer) -{ - /* TODO: test this: static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts); */ -} -END_TEST -START_TEST(tc_tcp_first_timeout) -{ - /* TODO: test this: static void tcp_first_timeout(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_tcp_rto_xmit) -{ - /* TODO: test this: static int tcp_rto_xmit(struct pico_socket_tcp *t, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_next_zerowindow_probe) -{ - /* TODO: test this: static void tcp_next_zerowindow_probe(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_tcp_is_allowed_to_send) -{ - /* TODO: test this: static int tcp_is_allowed_to_send(struct pico_socket_tcp *t) */ -} -END_TEST -START_TEST(tc_tcp_retrans_timeout) -{ - /* TODO: test this: static void tcp_retrans_timeout(pico_time val, void *sock) */ -} -END_TEST -START_TEST(tc_tcp_retrans) -{ - /* TODO: test this: static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_ack_dbg) -{ - /* TODO: test this: static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_ack) -{ - /* TODO: test this: static int tcp_ack(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_finwaitack) -{ - /* TODO: test this: static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_deltcb) -{ - /* TODO: test this: static void tcp_deltcb(pico_time when, void *arg) */ -} -END_TEST -START_TEST(tc_tcp_finwaitfin) -{ - /* TODO: test this: static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_closewaitack) -{ - /* TODO: test this: static int tcp_closewaitack(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_lastackwait) -{ - /* TODO: test this: static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_syn) -{ - /* TODO: test this: static int tcp_syn(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_set_init_point) -{ - /* TODO: test this: static void tcp_set_init_point(struct pico_socket *s) */ -} -END_TEST -START_TEST(tc_tcp_synack) -{ - /* TODO: test this: static int tcp_synack(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_first_ack) -{ - /* TODO: test this: static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_closewait) -{ - /* TODO: test this: static int tcp_closewait(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_fin) -{ - /* TODO: test this: static int tcp_fin(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_rcvfin) -{ - /* TODO: test this: static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_finack) -{ - /* TODO: test this: static int tcp_finack(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_force_closed) -{ - /* TODO: test this: static void tcp_force_closed(struct pico_socket *s) */ -} -END_TEST -START_TEST(tc_tcp_wakeup_pending) -{ - /* TODO: test this: static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev) */ -} -END_TEST -START_TEST(tc_tcp_rst) -{ - /* TODO: test this: static int tcp_rst(struct pico_socket *s, struct pico_frame *f) */ -} -END_TEST -START_TEST(tc_tcp_halfopencon) -{ - /* TODO: test this: static int tcp_halfopencon(struct pico_socket *s, struct pico_frame *fr) */ -} -END_TEST -START_TEST(tc_tcp_closeconn) -{ - /* TODO: test this: static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr) */ -} -END_TEST -START_TEST(tc_invalid_flags) -{ - /* TODO: test this: static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags) */ -} -END_TEST -START_TEST(tc_checkLocalClosing) -{ - /* TODO: test this: static int checkLocalClosing(struct pico_socket *s) */ -} -END_TEST -START_TEST(tc_checkRemoteClosing) -{ - /* TODO: test this: static int checkRemoteClosing(struct pico_socket *s) */ -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_input_segment_compare = tcase_create("Unit test for input_segment_compare"); - TCase *TCase_tcp_input_segment = tcase_create("Unit test for tcp_input_segment"); - TCase *TCase_segment_compare = tcase_create("Unit test for segment_compare"); - TCase *TCase_tcp_discard_all_segments = tcase_create("Unit test for tcp_discard_all_segments"); - TCase *TCase_release_until = tcase_create("Unit test for release_until"); - TCase *TCase_release_all_until = tcase_create("Unit test for release_all_until"); - TCase *TCase_tcp_send_fin = tcase_create("Unit test for tcp_send_fin"); - TCase *TCase_pico_tcp_process_out = tcase_create("Unit test for pico_tcp_process_out"); - TCase *TCase_pico_paws = tcase_create("Unit test for pico_paws"); - TCase *TCase_tcp_add_options = tcase_create("Unit test for tcp_add_options"); - TCase *TCase_tcp_options_size_frame = tcase_create("Unit test for tcp_options_size_frame"); - TCase *TCase_tcp_add_options_frame = tcase_create("Unit test for tcp_add_options_frame"); - TCase *TCase_tcp_send_ack = tcase_create("Unit test for tcp_send_ack"); - TCase *TCase_tcp_set_space = tcase_create("Unit test for tcp_set_space"); - TCase *TCase_tcp_options_size = tcase_create("Unit test for tcp_options_size"); - TCase *TCase_tcp_process_sack = tcase_create("Unit test for tcp_process_sack"); - TCase *TCase_tcp_rcv_sack = tcase_create("Unit test for tcp_rcv_sack"); - TCase *TCase_tcp_parse_options = tcase_create("Unit test for tcp_parse_options"); - TCase *TCase_tcp_send = tcase_create("Unit test for tcp_send"); - TCase *TCase_sock_stats = tcase_create("Unit test for sock_stats"); - TCase *TCase_initconn_retry = tcase_create("Unit test for initconn_retry"); - TCase *TCase_tcp_send_synack = tcase_create("Unit test for tcp_send_synack"); - TCase *TCase_tcp_send_empty = tcase_create("Unit test for tcp_send_empty"); - TCase *TCase_tcp_send_probe = tcase_create("Unit test for tcp_send_probe"); - TCase *TCase_tcp_send_rst = tcase_create("Unit test for tcp_send_rst"); - TCase *TCase_tcp_nosync_rst = tcase_create("Unit test for tcp_nosync_rst"); - TCase *TCase_tcp_sack_prepare = tcase_create("Unit test for tcp_sack_prepare"); - TCase *TCase_tcp_data_in = tcase_create("Unit test for tcp_data_in"); - TCase *TCase_tcp_ack_advance_una = tcase_create("Unit test for tcp_ack_advance_una"); - TCase *TCase_time_diff = tcase_create("Unit test for time_diff"); - TCase *TCase_tcp_rtt = tcase_create("Unit test for tcp_rtt"); - TCase *TCase_tcp_congestion_control = tcase_create("Unit test for tcp_congestion_control"); - TCase *TCase_add_retransmission_timer = tcase_create("Unit test for add_retransmission_timer"); - TCase *TCase_tcp_first_timeout = tcase_create("Unit test for tcp_first_timeout"); - TCase *TCase_tcp_rto_xmit = tcase_create("Unit test for tcp_rto_xmit"); - TCase *TCase_tcp_next_zerowindow_probe = tcase_create("Unit test for tcp_next_zerowindow_probe"); - TCase *TCase_tcp_is_allowed_to_send = tcase_create("Unit test for tcp_is_allowed_to_send"); - TCase *TCase_tcp_retrans_timeout = tcase_create("Unit test for tcp_retrans_timeout"); - TCase *TCase_tcp_retrans = tcase_create("Unit test for tcp_retrans"); - TCase *TCase_tcp_ack_dbg = tcase_create("Unit test for tcp_ack_dbg"); - TCase *TCase_tcp_ack = tcase_create("Unit test for tcp_ack"); - TCase *TCase_tcp_finwaitack = tcase_create("Unit test for tcp_finwaitack"); - TCase *TCase_tcp_deltcb = tcase_create("Unit test for tcp_deltcb"); - TCase *TCase_tcp_finwaitfin = tcase_create("Unit test for tcp_finwaitfin"); - TCase *TCase_tcp_closewaitack = tcase_create("Unit test for tcp_closewaitack"); - TCase *TCase_tcp_lastackwait = tcase_create("Unit test for tcp_lastackwait"); - TCase *TCase_tcp_syn = tcase_create("Unit test for tcp_syn"); - TCase *TCase_tcp_set_init_point = tcase_create("Unit test for tcp_set_init_point"); - TCase *TCase_tcp_synack = tcase_create("Unit test for tcp_synack"); - TCase *TCase_tcp_first_ack = tcase_create("Unit test for tcp_first_ack"); - TCase *TCase_tcp_closewait = tcase_create("Unit test for tcp_closewait"); - TCase *TCase_tcp_fin = tcase_create("Unit test for tcp_fin"); - TCase *TCase_tcp_rcvfin = tcase_create("Unit test for tcp_rcvfin"); - TCase *TCase_tcp_finack = tcase_create("Unit test for tcp_finack"); - TCase *TCase_tcp_force_closed = tcase_create("Unit test for tcp_force_closed"); - TCase *TCase_tcp_wakeup_pending = tcase_create("Unit test for tcp_wakeup_pending"); - TCase *TCase_tcp_rst = tcase_create("Unit test for tcp_rst"); - TCase *TCase_tcp_halfopencon = tcase_create("Unit test for tcp_halfopencon"); - TCase *TCase_tcp_closeconn = tcase_create("Unit test for tcp_closeconn"); - TCase *TCase_invalid_flags = tcase_create("Unit test for invalid_flags"); - TCase *TCase_checkLocalClosing = tcase_create("Unit test for checkLocalClosing"); - TCase *TCase_checkRemoteClosing = tcase_create("Unit test for checkRemoteClosing"); - - - tcase_add_test(TCase_input_segment_compare, tc_input_segment_compare); - suite_add_tcase(s, TCase_input_segment_compare); - tcase_add_test(TCase_tcp_input_segment, tc_tcp_input_segment); - suite_add_tcase(s, TCase_tcp_input_segment); - tcase_add_test(TCase_segment_compare, tc_segment_compare); - suite_add_tcase(s, TCase_segment_compare); - tcase_add_test(TCase_tcp_discard_all_segments, tc_tcp_discard_all_segments); - suite_add_tcase(s, TCase_tcp_discard_all_segments); - tcase_add_test(TCase_release_until, tc_release_until); - suite_add_tcase(s, TCase_release_until); - tcase_add_test(TCase_release_all_until, tc_release_all_until); - suite_add_tcase(s, TCase_release_all_until); - tcase_add_test(TCase_tcp_send_fin, tc_tcp_send_fin); - suite_add_tcase(s, TCase_tcp_send_fin); - tcase_add_test(TCase_pico_tcp_process_out, tc_pico_tcp_process_out); - suite_add_tcase(s, TCase_pico_tcp_process_out); - tcase_add_test(TCase_pico_paws, tc_pico_paws); - suite_add_tcase(s, TCase_pico_paws); - tcase_add_test(TCase_tcp_add_options, tc_tcp_add_options); - suite_add_tcase(s, TCase_tcp_add_options); - tcase_add_test(TCase_tcp_options_size_frame, tc_tcp_options_size_frame); - suite_add_tcase(s, TCase_tcp_options_size_frame); - tcase_add_test(TCase_tcp_add_options_frame, tc_tcp_add_options_frame); - suite_add_tcase(s, TCase_tcp_add_options_frame); - tcase_add_test(TCase_tcp_send_ack, tc_tcp_send_ack); - suite_add_tcase(s, TCase_tcp_send_ack); - tcase_add_test(TCase_tcp_set_space, tc_tcp_set_space); - suite_add_tcase(s, TCase_tcp_set_space); - tcase_add_test(TCase_tcp_options_size, tc_tcp_options_size); - suite_add_tcase(s, TCase_tcp_options_size); - tcase_add_test(TCase_tcp_process_sack, tc_tcp_process_sack); - suite_add_tcase(s, TCase_tcp_process_sack); - tcase_add_test(TCase_tcp_rcv_sack, tc_tcp_rcv_sack); - suite_add_tcase(s, TCase_tcp_rcv_sack); - tcase_add_test(TCase_tcp_parse_options, tc_tcp_parse_options); - suite_add_tcase(s, TCase_tcp_parse_options); - tcase_add_test(TCase_tcp_send, tc_tcp_send); - suite_add_tcase(s, TCase_tcp_send); - tcase_add_test(TCase_sock_stats, tc_sock_stats); - suite_add_tcase(s, TCase_sock_stats); - tcase_add_test(TCase_initconn_retry, tc_initconn_retry); - suite_add_tcase(s, TCase_initconn_retry); - tcase_add_test(TCase_tcp_send_synack, tc_tcp_send_synack); - suite_add_tcase(s, TCase_tcp_send_synack); - tcase_add_test(TCase_tcp_send_empty, tc_tcp_send_empty); - suite_add_tcase(s, TCase_tcp_send_empty); - tcase_add_test(TCase_tcp_send_probe, tc_tcp_send_probe); - suite_add_tcase(s, TCase_tcp_send_probe); - tcase_add_test(TCase_tcp_send_rst, tc_tcp_send_rst); - suite_add_tcase(s, TCase_tcp_send_rst); - tcase_add_test(TCase_tcp_nosync_rst, tc_tcp_nosync_rst); - suite_add_tcase(s, TCase_tcp_nosync_rst); - tcase_add_test(TCase_tcp_sack_prepare, tc_tcp_sack_prepare); - suite_add_tcase(s, TCase_tcp_sack_prepare); - tcase_add_test(TCase_tcp_data_in, tc_tcp_data_in); - suite_add_tcase(s, TCase_tcp_data_in); - tcase_add_test(TCase_tcp_ack_advance_una, tc_tcp_ack_advance_una); - suite_add_tcase(s, TCase_tcp_ack_advance_una); - tcase_add_test(TCase_time_diff, tc_time_diff); - suite_add_tcase(s, TCase_time_diff); - tcase_add_test(TCase_tcp_rtt, tc_tcp_rtt); - suite_add_tcase(s, TCase_tcp_rtt); - tcase_add_test(TCase_tcp_congestion_control, tc_tcp_congestion_control); - suite_add_tcase(s, TCase_tcp_congestion_control); - tcase_add_test(TCase_add_retransmission_timer, tc_add_retransmission_timer); - suite_add_tcase(s, TCase_add_retransmission_timer); - tcase_add_test(TCase_tcp_first_timeout, tc_tcp_first_timeout); - suite_add_tcase(s, TCase_tcp_first_timeout); - tcase_add_test(TCase_tcp_rto_xmit, tc_tcp_rto_xmit); - suite_add_tcase(s, TCase_tcp_rto_xmit); - tcase_add_test(TCase_tcp_next_zerowindow_probe, tc_tcp_next_zerowindow_probe); - suite_add_tcase(s, TCase_tcp_next_zerowindow_probe); - tcase_add_test(TCase_tcp_is_allowed_to_send, tc_tcp_is_allowed_to_send); - suite_add_tcase(s, TCase_tcp_is_allowed_to_send); - tcase_add_test(TCase_tcp_retrans_timeout, tc_tcp_retrans_timeout); - suite_add_tcase(s, TCase_tcp_retrans_timeout); - tcase_add_test(TCase_tcp_retrans, tc_tcp_retrans); - suite_add_tcase(s, TCase_tcp_retrans); - tcase_add_test(TCase_tcp_ack_dbg, tc_tcp_ack_dbg); - suite_add_tcase(s, TCase_tcp_ack_dbg); - tcase_add_test(TCase_tcp_ack, tc_tcp_ack); - suite_add_tcase(s, TCase_tcp_ack); - tcase_add_test(TCase_tcp_finwaitack, tc_tcp_finwaitack); - suite_add_tcase(s, TCase_tcp_finwaitack); - tcase_add_test(TCase_tcp_deltcb, tc_tcp_deltcb); - suite_add_tcase(s, TCase_tcp_deltcb); - tcase_add_test(TCase_tcp_finwaitfin, tc_tcp_finwaitfin); - suite_add_tcase(s, TCase_tcp_finwaitfin); - tcase_add_test(TCase_tcp_closewaitack, tc_tcp_closewaitack); - suite_add_tcase(s, TCase_tcp_closewaitack); - tcase_add_test(TCase_tcp_lastackwait, tc_tcp_lastackwait); - suite_add_tcase(s, TCase_tcp_lastackwait); - tcase_add_test(TCase_tcp_syn, tc_tcp_syn); - suite_add_tcase(s, TCase_tcp_syn); - tcase_add_test(TCase_tcp_set_init_point, tc_tcp_set_init_point); - suite_add_tcase(s, TCase_tcp_set_init_point); - tcase_add_test(TCase_tcp_synack, tc_tcp_synack); - suite_add_tcase(s, TCase_tcp_synack); - tcase_add_test(TCase_tcp_first_ack, tc_tcp_first_ack); - suite_add_tcase(s, TCase_tcp_first_ack); - tcase_add_test(TCase_tcp_closewait, tc_tcp_closewait); - suite_add_tcase(s, TCase_tcp_closewait); - tcase_add_test(TCase_tcp_fin, tc_tcp_fin); - suite_add_tcase(s, TCase_tcp_fin); - tcase_add_test(TCase_tcp_rcvfin, tc_tcp_rcvfin); - suite_add_tcase(s, TCase_tcp_rcvfin); - tcase_add_test(TCase_tcp_finack, tc_tcp_finack); - suite_add_tcase(s, TCase_tcp_finack); - tcase_add_test(TCase_tcp_force_closed, tc_tcp_force_closed); - suite_add_tcase(s, TCase_tcp_force_closed); - tcase_add_test(TCase_tcp_wakeup_pending, tc_tcp_wakeup_pending); - suite_add_tcase(s, TCase_tcp_wakeup_pending); - tcase_add_test(TCase_tcp_rst, tc_tcp_rst); - suite_add_tcase(s, TCase_tcp_rst); - tcase_add_test(TCase_tcp_halfopencon, tc_tcp_halfopencon); - suite_add_tcase(s, TCase_tcp_halfopencon); - tcase_add_test(TCase_tcp_closeconn, tc_tcp_closeconn); - suite_add_tcase(s, TCase_tcp_closeconn); - tcase_add_test(TCase_invalid_flags, tc_invalid_flags); - suite_add_tcase(s, TCase_invalid_flags); - tcase_add_test(TCase_checkLocalClosing, tc_checkLocalClosing); - suite_add_tcase(s, TCase_checkLocalClosing); - tcase_add_test(TCase_checkRemoteClosing, tc_checkRemoteClosing); - suite_add_tcase(s, TCase_checkRemoteClosing); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_pico_tftp.c b/ext/picotcp/test/unit/modunit_pico_tftp.c deleted file mode 100644 index 3d6cfd1..0000000 --- a/ext/picotcp/test/unit/modunit_pico_tftp.c +++ /dev/null @@ -1,375 +0,0 @@ -#include -#include -#include -#include -#include "modules/pico_tftp.c" -#include "check.h" - - -Suite *pico_suite(void); -int tftp_user_cb(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg); -/* MOCKS */ -static int called_pico_socket_close = 0; -static uint16_t expected_opcode = 0; -static int called_user_cb = 0; -static int called_sendto = 0; -static uint32_t called_pico_timer_add = 0; -static int called_pico_timer_cancel = 0; -static struct pico_socket example_socket; -static struct pico_tftp_session example_session; - -int pico_socket_close(struct pico_socket *s) -{ - fail_if(s != example_session.socket); - called_pico_socket_close++; - return 0; -} - -int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) -{ - const struct pico_tftp_hdr *h = (const struct pico_tftp_hdr *)buf; - fail_if(s != &example_socket); - fail_if(short_be(h->opcode) != expected_opcode); - fail_if(len <= 0); - (void)dst; - (void)remote_port; - called_sendto++; - return 0; -} - -int tftp_user_cb(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg) -{ - (void)session; - (void)err; - (void)block; - (void)len; - (void)arg; - called_user_cb++; - return 0; -} - -uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - (void)expire; - (void)timer; - (void)arg; - - return ++called_pico_timer_add; -} - -void pico_timer_cancel(uint32_t t) -{ - (void)t; - called_pico_timer_cancel++; -} - -/* TESTS */ - -/* START_TEST(tc_check_opcode) */ -/* { */ -/* / * TODO: test this: static int check_opcode(struct pico_tftp_hdr *th) * / */ -/* struct pico_tftp_hdr th; */ -/* th.opcode = 0; */ -/* fail_unless(check_opcode(&th) == -1); */ -/* th.opcode = short_be(PICO_TFTP_RRQ); */ -/* fail_unless(check_opcode(&th) == 0); */ -/* th.opcode = short_be(0xFF); */ -/* fail_unless(check_opcode(&th) == -1); */ -/* } */ -/* END_TEST */ - - -START_TEST(tc_find_session_by_socket) -{ - tftp_sessions = (struct pico_tftp_session *)PICO_ZALLOC(sizeof(struct pico_tftp_session)); - tftp_sessions->socket = &example_socket; - tftp_sessions->next = (struct pico_tftp_session *)PICO_ZALLOC(sizeof(struct pico_tftp_session)); - tftp_sessions->socket = NULL; - tftp_sessions->next = NULL; - fail_if(find_session_by_socket(&example_socket) != tftp_sessions->next); -} -END_TEST - -START_TEST(tc_tftp_finish) -{ - tftp_sessions = 0; - - /* Test case: client */ - example_session.socket = &example_socket; - called_pico_socket_close = 0; - tftp_finish(&example_session); - fail_if(!called_pico_socket_close); - - /* Test eval_finish() len is 5*/ - example_session.socket = &example_socket; - called_pico_socket_close = 0; - tftp_eval_finish(&example_session, 5); - fail_if(example_session.state != TFTP_STATE_CLOSING); - fail_if(!called_pico_socket_close); - - /* Test eval_finish() len is PICO_TFTP_TOTAL_BLOCK_SIZE */ - example_session.socket = &example_socket; - called_pico_socket_close = 0; - tftp_eval_finish(&example_session, PICO_TFTP_TOTAL_BLOCK_SIZE); - fail_if(called_pico_socket_close); -} -END_TEST - -START_TEST(tc_tftp_send_ack) -{ - example_session.socket = &example_socket; -#ifdef PICO_FAULTY - /* send_ack must not segfault when out of memory */ - pico_set_mm_failure(1); - tftp_send_ack(&example_session); - fail_if(called_sendto > 0); -#endif - expected_opcode = PICO_TFTP_ACK; - tftp_send_ack(&example_session); - fail_if(called_sendto < 1); - -} -END_TEST - -START_TEST(tc_tftp_send_req) -{ - /* Not needed. The tftp_send_rx_req and tftp_send_tx_req cover this. */ -} -END_TEST - -START_TEST(tc_tftp_send_rx_req) -{ - char filename[14] = "some filename"; - - example_session.socket = &example_socket; - called_user_cb = 0; - called_pico_socket_close = 0; - called_sendto = 0; -#ifdef PICO_FAULTY - example_session.callback = tftp_user_cb; - - /* send_req must call error cb when out of memory */ - pico_set_mm_failure(1); - tftp_send_rx_req(&example_session, NULL, 0, filename); - fail_if(called_user_cb < 1); - fail_if(called_sendto > 0); -#endif - expected_opcode = PICO_TFTP_RRQ; - tftp_send_rx_req(&example_session, NULL, 0, NULL); - fail_if(called_sendto > 0); /* Calling with filename = NULL: not good */ - - tftp_send_rx_req(&example_session, NULL, 0, filename); - fail_if(called_sendto < 0); -} -END_TEST - -START_TEST(tc_tftp_send_tx_req) -{ - char filename[14] = "some filename"; - - example_session.socket = &example_socket; - called_user_cb = 0; - called_pico_socket_close = 0; - called_sendto = 0; -#ifdef PICO_FAULTY - example_session.callback = tftp_user_cb; - - /* send_req must call error cb when out of memory */ - pico_set_mm_failure(1); - tftp_send_tx_req(&example_session, NULL, 0, filename); - fail_if(called_user_cb < 1); - fail_if(called_sendto > 0); -#endif - expected_opcode = PICO_TFTP_WRQ; - tftp_send_tx_req(&example_session, NULL, 0, NULL); - fail_if(called_sendto > 0); /* Calling with filename = NULL: not good */ - - tftp_send_tx_req(&example_session, NULL, 0, filename); - fail_if(called_sendto < 0); -} -END_TEST - -START_TEST(tc_tftp_send_error) -{ - char longtext[1024]; - example_session.socket = &example_socket; - called_user_cb = 0; - called_pico_socket_close = 0; - - /* Sending empty msg */ - called_sendto = 0; - expected_opcode = PICO_TFTP_ERROR; - tftp_send_error(&example_session, NULL, 0, 0, NULL); - fail_if(called_sendto < 1); - /* Sending some msg */ - called_sendto = 0; - expected_opcode = PICO_TFTP_ERROR; - tftp_send_error(&example_session, NULL, 0, 0, "some text here"); - fail_if(called_sendto < 1); - - /* sending some very long msg */ - memset(longtext, 'a', 1023); - longtext[1023] = (char)0; - called_sendto = 0; - expected_opcode = PICO_TFTP_ERROR; - tftp_send_error(&example_session, NULL, 0, 0, longtext); - fail_if(called_sendto < 1); -} -END_TEST - -START_TEST(tc_tftp_send_data) -{ - example_session.state = 0; - example_session.socket = &example_socket; - called_sendto = 0; - expected_opcode = PICO_TFTP_DATA; - tftp_send_data(&example_session, (const uint8_t*)"buffer", strlen("buffer")); - fail_if(called_sendto < 1); - fail_if(example_session.state != TFTP_STATE_WAIT_LAST_ACK); -} -END_TEST - -START_TEST(tc_pico_tftp_abort) -{ - int ret; - server.listen_socket = NULL; - - /*first case: no session and no listening socket*/ - ret = pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test"); - fail_if(ret != -1); - /*second case: no session but listening socket*/ - server.listen_socket = example_session.socket = &example_socket; - pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test"); - fail_if(ret != -1); - /*tirdh case: session non into list*/ - ret = pico_tftp_abort(&example_session, TFTP_ERR_EUSR, "test"); - fail_if(ret != -1); -} -END_TEST - -/* Receiving functions */ - -START_TEST(tc_tftp_data) -{ - /* TODO: test this: static void tftp_data(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */ -} -END_TEST -START_TEST(tc_tftp_ack) -{ - /* TODO: test this: static void tftp_ack(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */ -} -END_TEST -START_TEST(tc_tftp_timeout) -{ - /* TODO: test this: static void tftp_timeout(pico_time t) */ -} -END_TEST -START_TEST(tc_tftp_req) -{ - /* TODO: test this: static void tftp_req(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */ -} -END_TEST -START_TEST(tc_tftp_data_err) -{ - /* TODO: test this: static void tftp_data_err(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */ -} -END_TEST -START_TEST(tc_tftp_fsm_timeout) -{ - /* TODO: test this: static void tftp_fsm_timeout(pico_time now, void *arg) */ -} -END_TEST -START_TEST(tc_tftp_receive) -{ - /* TODO: test this: static void tftp_receive(uint8_t *block, uint32_t r, union pico_address *a, uint16_t port) */ -} -END_TEST -START_TEST(tc_tftp_cb) -{ - /* TODO: test this: static void tftp_cb(uint16_t ev, struct pico_socket *s) */ -} -END_TEST -START_TEST(tc_tftp_socket_open) -{ - /* TODO: test this: static int tftp_socket_open(uint16_t family, union pico_address *a, uint16_t port) */ - fail_if(tftp_socket_open(0xFFFF, 21) != NULL); - fail_if(tftp_socket_open(0xFFFF, 0xFFFF) != NULL); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - -/* TCase *TCase_check_opcode = tcase_create("Unit test for check_opcode"); */ - TCase *TCase_find_session_by_socket = tcase_create("Unit test for find_session_by_socket"); - TCase *TCase_tftp_finish = tcase_create("Unit test for tftp_finish"); - TCase *TCase_tftp_send_ack = tcase_create("Unit test for tftp_send_ack"); - TCase *TCase_tftp_send_req = tcase_create("Unit test for tftp_send_req"); - TCase *TCase_tftp_send_rx_req = tcase_create("Unit test for tftp_send_rx_req"); - TCase *TCase_tftp_send_tx_req = tcase_create("Unit test for tftp_send_tx_req"); - TCase *TCase_tftp_send_error = tcase_create("Unit test for tftp_send_error"); - TCase *TCase_tftp_send_data = tcase_create("Unit test for tftp_send_data"); - TCase *Tcase_pico_tftp_abort = tcase_create("Unit test for pico_tftp_abort"); - TCase *TCase_tftp_data = tcase_create("Unit test for tftp_data"); - TCase *TCase_tftp_ack = tcase_create("Unit test for tftp_ack"); - TCase *TCase_tftp_timeout = tcase_create("Unit test for tftp_timeout"); - TCase *TCase_tftp_req = tcase_create("Unit test for tftp_req"); - TCase *TCase_tftp_data_err = tcase_create("Unit test for tftp_data_err"); - TCase *TCase_tftp_fsm_timeout = tcase_create("Unit test for tftp_fsm_timeout"); - TCase *TCase_tftp_receive = tcase_create("Unit test for tftp_receive"); - TCase *TCase_tftp_cb = tcase_create("Unit test for tftp_cb"); - TCase *TCase_tftp_socket_open = tcase_create("Unit test for tftp_socket_open"); - - -/* tcase_add_test(TCase_check_opcode, tc_check_opcode); */ -/* suite_add_tcase(s, TCase_check_opcode); */ - tcase_add_test(TCase_find_session_by_socket, tc_find_session_by_socket); - suite_add_tcase(s, TCase_find_session_by_socket); - tcase_add_test(TCase_tftp_finish, tc_tftp_finish); - suite_add_tcase(s, TCase_tftp_finish); - tcase_add_test(TCase_tftp_send_ack, tc_tftp_send_ack); - suite_add_tcase(s, TCase_tftp_send_ack); - tcase_add_test(TCase_tftp_send_req, tc_tftp_send_req); - suite_add_tcase(s, TCase_tftp_send_req); - tcase_add_test(TCase_tftp_send_rx_req, tc_tftp_send_rx_req); - suite_add_tcase(s, TCase_tftp_send_rx_req); - tcase_add_test(TCase_tftp_send_tx_req, tc_tftp_send_tx_req); - suite_add_tcase(s, TCase_tftp_send_tx_req); - tcase_add_test(TCase_tftp_send_error, tc_tftp_send_error); - suite_add_tcase(s, TCase_tftp_send_error); - tcase_add_test(TCase_tftp_send_data, tc_tftp_send_data); - suite_add_tcase(s, TCase_tftp_send_data); - tcase_add_test(TCase_tftp_data, tc_tftp_data); - suite_add_tcase(s, Tcase_pico_tftp_abort); - tcase_add_test(Tcase_pico_tftp_abort, tc_pico_tftp_abort); - suite_add_tcase(s, TCase_tftp_data); - tcase_add_test(TCase_tftp_ack, tc_tftp_ack); - suite_add_tcase(s, TCase_tftp_ack); - tcase_add_test(TCase_tftp_timeout, tc_tftp_timeout); - suite_add_tcase(s, TCase_tftp_timeout); - tcase_add_test(TCase_tftp_req, tc_tftp_req); - suite_add_tcase(s, TCase_tftp_req); - tcase_add_test(TCase_tftp_data_err, tc_tftp_data_err); - suite_add_tcase(s, TCase_tftp_data_err); - tcase_add_test(TCase_tftp_fsm_timeout, tc_tftp_fsm_timeout); - suite_add_tcase(s, TCase_tftp_fsm_timeout); - tcase_add_test(TCase_tftp_receive, tc_tftp_receive); - suite_add_tcase(s, TCase_tftp_receive); - tcase_add_test(TCase_tftp_cb, tc_tftp_cb); - suite_add_tcase(s, TCase_tftp_cb); - tcase_add_test(TCase_tftp_socket_open, tc_tftp_socket_open); - suite_add_tcase(s, TCase_tftp_socket_open); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_queue.c b/ext/picotcp/test/unit/modunit_queue.c deleted file mode 100644 index 9d13aa3..0000000 --- a/ext/picotcp/test/unit/modunit_queue.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "pico_frame.h" -#include "pico_queue.h" -#include "stack/pico_frame.c" -#include "pico_stack.h" -#include "check.h" - - -Suite *pico_suite(void); - -struct pico_queue q1 = { - 0 -}, q2 = { - 0 -}; - -START_TEST(tc_q) -{ - struct pico_frame *f0 = pico_frame_alloc(100); - struct pico_frame *f1 = pico_frame_alloc(100); - struct pico_frame *f2 = pico_frame_alloc(100); - struct pico_frame *f3 = pico_frame_alloc(100); - struct pico_frame *f4 = pico_frame_alloc(100); - - pico_queue_protect(&q1); - - q1.max_frames = 4; - q2.max_size = 4 * 100; - - fail_if (pico_enqueue(&q1, pico_frame_copy(f0)) < 0); - fail_if (pico_enqueue(&q1, pico_frame_copy(f1)) < 0); - fail_if (pico_enqueue(&q1, pico_frame_copy(f2)) < 0); - fail_if (pico_enqueue(&q1, pico_frame_copy(f3)) < 0); - fail_if (pico_enqueue(&q1, pico_frame_copy(f4)) >= 0); - - fail_if (pico_enqueue(&q2, pico_frame_copy(f0)) < 0); - fail_if (pico_enqueue(&q2, pico_frame_copy(f1)) < 0); - fail_if (pico_enqueue(&q2, pico_frame_copy(f2)) < 0); - fail_if (pico_enqueue(&q2, pico_frame_copy(f3)) < 0); - fail_if (pico_enqueue(&q2, pico_frame_copy(f4)) >= 0); - - fail_if((pico_dequeue(&q1))->buffer != f0->buffer); - fail_if((pico_dequeue(&q1))->buffer != f1->buffer); - fail_if((pico_dequeue(&q1))->buffer != f2->buffer); - fail_if((pico_dequeue(&q1))->buffer != f3->buffer); - fail_if(pico_queue_peek(&q1) != NULL); - fail_if(pico_dequeue(&q1) != NULL); - fail_if(q1.size != 0); - fail_if(q1.frames != 0); - - - pico_queue_empty(&q2); - fail_if(q2.size != 0); - fail_if(q2.frames != 0); - fail_if(pico_queue_peek(&q2) != NULL); - fail_if(pico_dequeue(&q2) != NULL); - - pico_queue_deinit(&q1); - pico_queue_deinit(&q2); - - -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("Packet Queues"); - - TCase *TCase_q = tcase_create("Unit test for pico_queue.c"); - tcase_add_test(TCase_q, tc_q); - suite_add_tcase(s, TCase_q); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/modunit_seq.c b/ext/picotcp/test/unit/modunit_seq.c deleted file mode 100644 index 0c1c2c4..0000000 --- a/ext/picotcp/test/unit/modunit_seq.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "pico_tcp.c" -#include - -Suite *pico_suite(void); - -START_TEST(tc_seq_compare) -{ - uint32_t big_a = 0xFFFFFF0alu; - uint32_t big_b = 0xFFFFFF0blu; - uint32_t small_a = 0xalu; - uint32_t small_b = 0xblu; - uint32_t under_thresh = 0x7ffffffflu; - uint32_t over_thresh = 0x80000000lu; - uint32_t zero = 0lu; - - fail_if(pico_seq_compare(small_a, small_b) >= 0); - fail_if(pico_seq_compare(small_b, small_a) <= 0); - - fail_if(pico_seq_compare(over_thresh, under_thresh) <= 0); - fail_if(pico_seq_compare(under_thresh, over_thresh) >= 0); - - fail_if(pico_seq_compare(small_a, big_b) <= 0); - fail_if(pico_seq_compare(big_b, small_a) >= 0); - - fail_if(pico_seq_compare(small_a, zero) <= 0); - fail_if(pico_seq_compare(zero, small_a) >= 0); - - fail_if(pico_seq_compare(big_a, zero) >= 0); - fail_if(pico_seq_compare(zero, big_a) <= 0); - - fail_if(pico_seq_compare(big_a, big_b) >= 0); - fail_if(pico_seq_compare(big_b, big_a) <= 0); - - fail_if(pico_seq_compare(big_a, big_a) != 0); - fail_if(pico_seq_compare(zero, zero) != 0); - -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("pico tcp sequence numbers"); - TCase *TCase_seq_compare = tcase_create("Unit test for pico_seq_compare"); - tcase_add_test(TCase_seq_compare, tc_seq_compare); - suite_add_tcase(s, TCase_seq_compare); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} - diff --git a/ext/picotcp/test/unit/unit_arp.c b/ext/picotcp/test/unit/unit_arp.c deleted file mode 100644 index c6684bf..0000000 --- a/ext/picotcp/test/unit/unit_arp.c +++ /dev/null @@ -1,213 +0,0 @@ -#include "pico_ethernet.c" - -static struct pico_frame *init_frame(struct pico_device *dev) -{ - struct pico_frame *f = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR); - f->net_hdr = f->buffer + PICO_SIZE_ETHHDR; - f->datalink_hdr = f->buffer; - f->dev = dev; - - return f; -} - -START_TEST (arp_update_max_arp_reqs_test) -{ - pico_stack_init(); - max_arp_reqs = 0; - usleep((PICO_ARP_INTERVAL + 1) * 1000); - pico_stack_tick(); - fail_unless(max_arp_reqs > 0); - - max_arp_reqs = PICO_ARP_MAX_RATE; - usleep((PICO_ARP_INTERVAL + 1) * 1000); - pico_stack_tick(); - fail_unless(max_arp_reqs == PICO_ARP_MAX_RATE); -} -END_TEST - -START_TEST (arp_compare_test) -{ - struct pico_arp a, b; - char ipstr[] = "192.168.1.1"; - - memset(&a, 0, sizeof(a)); - pico_string_to_ipv4(ipstr, &b.ipv4.addr); - - fail_unless(arp_compare(&a, &b) == -1); - fail_unless(arp_compare(&b, &a) == 1); - fail_unless(arp_compare(&a, &a) == 0); -} -END_TEST - -START_TEST (arp_lookup_test) -{ - struct pico_ip4 ip; - struct pico_eth *eth = NULL; - char ipstr[] = "192.168.1.1"; - struct pico_arp entry; - - eth = pico_arp_lookup(&ip); - fail_unless(eth == NULL); - - pico_string_to_ipv4(ipstr, &ip.addr); - entry.ipv4 = ip; - - pico_stack_init(); - fail_unless(pico_arp_add_entry(&entry) == 0); - entry.arp_status = PICO_ARP_STATUS_STALE; - eth = pico_arp_lookup(&ip); - fail_unless(eth == NULL); - pico_tree_delete(&arp_tree, &entry); -} -END_TEST - -START_TEST (arp_expire_test) -{ - struct pico_arp entry; - entry.arp_status = PICO_ARP_STATUS_REACHABLE; - entry.timestamp = 0; - - arp_expire(PICO_ARP_TIMEOUT, &entry); - fail_unless(entry.arp_status == PICO_ARP_STATUS_STALE); -} -END_TEST - -START_TEST(tc_pico_arp_queue) -{ - struct pico_ip4 addr = { - .addr = 0xaabbccdd - }; - int i; - struct pico_frame *f = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); - struct pico_ipv4_hdr *h = (struct pico_ipv4_hdr *) f->buffer; - fail_if(!f); - f->net_hdr = (uint8_t *)h; - h->dst.addr = addr.addr; - - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) { - fail_if(frames_queued[i] != NULL); - } - pico_arp_unreachable(&addr); - for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) { - fail_if(frames_queued[i] != NULL); - } - pico_arp_postpone(f); - fail_if(frames_queued[0]->buffer != f->buffer); - pico_arp_unreachable(&addr); - PICO_FREE(f); -} -END_TEST - - - -START_TEST (arp_receive_test) -{ - struct mock_device *mock; - struct pico_frame *f = NULL; - struct pico_arp_hdr *ah = NULL; - struct pico_eth_hdr *eh = NULL; - uint8_t macaddr1[6] = { - 0, 0, 0, 0xa, 0xb, 0xf - }; - uint8_t macaddr2[6] = { - 0, 0, 0, 0xc, 0xd, 0xf - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct pico_ip4 ip1 = { - .addr = long_be(0x0A2800AA) - }; - struct pico_ip4 ip2 = { - .addr = long_be(0x0A2800AB) - }; - - pico_stack_init(); - - /* Create mock device */ - mock = pico_mock_create(macaddr1); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_ipv4_link_add(mock->dev, ip1, netmask), "add link to mock device failed"); - - /* Normal ARP request */ - f = init_frame(mock->dev); - fail_if(!f, "FRAME INIT failed"); - eh = (struct pico_eth_hdr *) f->datalink_hdr; - ah = (struct pico_arp_hdr *) f->net_hdr; - - memcpy(eh->saddr, macaddr2, PICO_SIZE_ETH); - memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH); - eh->proto = PICO_IDETH_ARP; - - 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, macaddr2, PICO_SIZE_ETH); - ah->src.addr = ip2.addr; - ah->dst.addr = ip1.addr; - fail_unless(pico_arp_receive(f) == 0); - - /* net_hdr is a nullpointer */ - f = init_frame(mock->dev); - fail_if(!f, "FRAME INIT failed"); - f->net_hdr = NULL; - fail_unless(pico_arp_receive(f) == -1); - - /* wrong hardware type */ - f = init_frame(mock->dev); - fail_if(!f, "FRAME INIT failed"); - ah = (struct pico_arp_hdr *) f->net_hdr; - ah->htype = 0; - fail_unless(pico_arp_receive(f) == -1); - - /* wrong protocol type */ - f = init_frame(mock->dev); - fail_if(!f, "FRAME INIT failed"); - ah = (struct pico_arp_hdr *) f->net_hdr; - ah->ptype = 0; - fail_unless(pico_arp_receive(f) == -1); - - /* source mac address is multicast */ - f = init_frame(mock->dev); - fail_if(!f, "FRAME INIT failed"); - ah = (struct pico_arp_hdr *) f->net_hdr; - ah->s_mac[0] = 0x01; - fail_unless(pico_arp_receive(f) == -1); - pico_ipv4_link_del(mock->dev, ip1); -} -END_TEST - -START_TEST (arp_get_test) -{ - struct pico_frame *f = NULL; - struct mock_device *mock; - struct pico_ipv4_hdr *hdr = NULL; - struct pico_eth *eth = NULL; - uint8_t macaddr[6] = { - 0, 0, 0xa, 0xa, 0xb, 0xf - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct pico_ip4 ip = { - .addr = long_be(0x0A28000B) - }; - - mock = pico_mock_create(macaddr); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_ipv4_link_add(mock->dev, ip, netmask), "add link to mock device failed"); - - f = pico_frame_alloc(PICO_SIZE_ETHHDR + sizeof(struct pico_ipv4_hdr)); - f->net_hdr = f->start + PICO_SIZE_ETHHDR; - f->datalink_hdr = f->start; - f->dev = mock->dev; - - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - hdr->dst.addr = ip.addr; - eth = pico_arp_get(f); - fail_unless(eth == &mock->dev->eth->mac); - pico_ipv4_link_del(mock->dev, ip); -} -END_TEST diff --git a/ext/picotcp/test/unit/unit_dhcp.c b/ext/picotcp/test/unit/unit_dhcp.c deleted file mode 100644 index 08124b9..0000000 --- a/ext/picotcp/test/unit/unit_dhcp.c +++ /dev/null @@ -1,554 +0,0 @@ - -static struct pico_dhcp_client_cookie*dhcp_client_ptr; - -void callback_dhcpclient(void*cli, int code); -int generate_dhcp_msg(uint8_t *buf, uint32_t *len, uint8_t type); - -void callback_dhcpclient(void*cli, int code) -{ - struct pico_ip4 gateway; - char gw_txt_addr[30]; - IGNORE_PARAMETER(cli); - - if(code == PICO_DHCP_SUCCESS) { - gateway = pico_dhcp_get_gateway(&dhcp_client_ptr); - pico_ipv4_to_string(gw_txt_addr, gateway.addr); - } - - printf("callback happened with code %d!\n", code); -} - -int generate_dhcp_msg(uint8_t *buf, uint32_t *len, uint8_t type) -{ - if(type == DHCP_MSG_TYPE_DISCOVER) { - uint8_t buffer[] = { - 0x01, 0x01, 0x06, 0x00, 0x0c, 0x10, - 0x53, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x0a, 0x0b, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x01, 0x37, 0x07, 0x01, - 0x1c, 0x02, 0x03, 0x0c, 0x3a, 0x3b, 0x39, 0x02, 0x02, 0x40, 0xff, 0x00 - }; - *len = sizeof(buffer); - memcpy(&(buf[0]), buffer, *len); - }else if(type == DHCP_MSG_TYPE_OFFER) { - return 1; - }else if(type == DHCP_MSG_TYPE_REQUEST) { - uint32_t i = 0; - uint8_t buffer1[] = { - /* 0x63,0x82,0x53,0x63,// MAGIC COOCKIE */ - /* 0x35,0x01,0x03, // DHCP REQUEST */ - /* 0x36,0x04,0x00,0x00,0x00,0x00 // SERVER ID */ - 0x32, 0x04, buf[0x3a], buf[0x3b], buf[0x3c], buf[0x3e], /* requested ip */ - 0x37, 0x04, 0x01, 0x03, 0x06, 0x2a, /* Parameter list */ - 0x3d, 0x07, 0x01, buf[0x06], buf[0x07], buf[0x08], buf[0x09], buf[0x0a], buf[0x0b], /* Client id */ - 0xff - }; - - buf[0x02a] = 0x01; /* change to boot request */ - buf[0x11c] = 0x03; /* request */ - - memcpy(&(buf[0x123]), &(buffer1[0]), sizeof(buffer1)); - *len = sizeof(buffer1) + 0x123; - for(i = *len; i < 0x150; i++) { - buf[i + 10] = 0x00; - } - return 0; - }else if(type == DHCP_MSG_TYPE_ACK) { - return 1; - } - - return 0; -} - -START_TEST (test_dhcp_server_api) -{ -/************************************************************************ - * Check if dhcp recv works correctly if - * MAC address of client is not in arp table yet - * Status : Done - ************************************************************************/ - - struct mock_device *mock; - uint8_t macaddr1[6] = { - 0xc1, 0, 0, 0xa, 0xb, 0xf - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct pico_ip4 serverip = { - .addr = long_be(0x0A28000A) - }; - uint8_t buf[600] = { - 0 - }; - /* Declaration test 1 */ - struct pico_dhcp_server_setting s1 = { - 0 - }; - /* Declaration test 2 */ - struct pico_dhcp_server_setting s2 = { - 0 - }; - - printf("*********************** starting %s * \n", __func__); - - /* Create mock device */ - mock = pico_mock_create(macaddr1); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_mock_network_read(mock, buf, BUFLEN), "data on network that shouldn't be there"); - fail_if(pico_ipv4_link_add(mock->dev, serverip, netmask), "add link to mock device failed"); - - /* test 0 */ - /* Clear error code */ - pico_err = PICO_ERR_NOERR; - /* Test 0 statements */ - fail_unless(pico_dhcp_server_initiate(NULL), "DHCP_SERVER> initiate succeeded after pointer to dev == NULL"); - fail_unless(pico_err == PICO_ERR_EINVAL, "DHCP_SERVER> initiate succeeded without PICO_ERR_EINVAL after wrong parameter"); - - /* test 1 */ - /* Clear error code */ - pico_err = PICO_ERR_NOERR; - /* Store data in settings */ - s1.server_ip.addr = long_be(0x0A28000F); /* make sure this IP is not assigned */ - /* Test 1 statements */ - fail_unless(pico_dhcp_server_initiate(&s1), "DHCP_SERVER> initiate succeeded after pointer to dev == NULL"); - fail_unless(pico_err == PICO_ERR_EINVAL, "DHCP_SERVER> initiate succeeded without PICO_ERR_EINVAL after wrong parameter"); - - /* test 2 */ - /* Clear error code */ - pico_err = PICO_ERR_NOERR; - /* Store data in settings */ - s2.server_ip = serverip; - /* Test 2 statements */ - fail_if(pico_dhcp_server_initiate(&s2), "DHCP_SERVER> failed after correct parameter"); -} -END_TEST - -START_TEST (test_dhcp) -{ -/************************************************************************ - * Check if all states (offer, bound) are changed correctly - * and if response messages are replied correctly - * Status : Done - *************************************************************************/ - struct mock_device*mock; - struct pico_dhcp_server_setting s = { - 0 - }; - struct pico_ip4 xid = { - .addr = long_be(0x00003d1d) - }; - uint8_t macaddr1[6] = { - 0xc1, 0, 0, 0xa, 0xb, 0xf - }; - uint8_t macaddr2[6] = { - 0xc6, 0, 0, 0xa, 0xb, 0xf - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct pico_ip4 serverip = { - .addr = long_be(0x0A28000A) - }; - struct pico_socket sock = { }; - struct pico_dhcp_server_negotiation *dn = NULL; - struct pico_ip4 *stored_ipv4 = NULL; - uint32_t len = 0; - int network_read = 0; - uint8_t *buf; - uint8_t printbufactive = 0; - - buf = PICO_ZALLOC(600); - - printf("*********************** starting %s * \n", __func__); - - /*Insert custom values in buffer*/ - fail_if(generate_dhcp_msg(buf, &len, DHCP_MSG_TYPE_DISCOVER), "DHCP_SERVER->failed to generate buffer"); - memcpy(&(buf[4]), &(xid.addr), sizeof(struct pico_ip4)); - memcpy(&(buf[28]), &(macaddr1[0]), sizeof(struct pico_ip4)); - printbuf(&(buf[0]), len, "DHCP-DISCOVER packet", printbufactive); - - /*Initiate test setup*/ - pico_stack_init(); - - /* Create mock device */ - mock = pico_mock_create(macaddr2); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_mock_network_read(mock, buf, BUFLEN), "data on network that shouldn't be there"); - fail_if(pico_ipv4_link_add(mock->dev, serverip, netmask), "add link to mock device failed"); - - s.server_ip = serverip; - - fail_if(pico_dhcp_server_initiate(&s), "DHCP_SERVER> server initiation failed"); - - dn = pico_dhcp_server_find_negotiation(xid.addr); - fail_unless(dn == NULL, "DCHP SERVER -> negotiation data available befor discover msg recvd"); - - /* simulate reception of a DISCOVER packet */ - sock.local_addr.ip4 = serverip; - pico_dhcp_server_recv(&sock, buf, len); - - tick_it(3); - - /* check if negotiation data is stored */ - dn = pico_dhcp_server_find_negotiation(xid.addr); - fail_if(dn == NULL, "DCHP SERVER -> no negotiation stored after discover msg recvd"); - - /* check if new ip is in ARP cache */ - stored_ipv4 = pico_arp_reverse_lookup(&dn->hwaddr); - fail_if(stored_ipv4 == NULL, "DCHP SERVER -> new address is not inserted in ARP"); - fail_unless(stored_ipv4->addr == dn->ciaddr.addr, "DCHP SERVER -> new ip not stored in negotiation data"); - - /* check if state is changed and reply is received */ - network_read = pico_mock_network_read(mock, buf, BUFLEN); - fail_unless(network_read > 0, "received msg on network of %u bytes", network_read); - printbuf(&(buf[0]), (uint32_t)network_read, "DHCP-OFFER msg", printbufactive); - fail_unless(buf[0x011c] == 0x02, "No DHCP offer received after discovery"); - fail_unless(dn->state == PICO_DHCP_STATE_OFFER, "DCHP SERVER -> negotiation state not changed to OFFER"); - - /*change offer to request*/ - fail_if(generate_dhcp_msg(buf, &len, DHCP_MSG_TYPE_REQUEST), "DHCP_SERVER->failed to generate buffer"); - printbuf(&(buf[0x2a]), len - 0x2a, "request buffer", printbufactive); - - /* simulate reception of a offer packet */ - pico_dhcp_server_recv(&sock, &(buf[0x2a]), len - 0x2a); - fail_unless(dn->state == PICO_DHCP_STATE_BOUND, "DCHP SERVER -> negotiation state not changed to BOUND"); - - tick_it(3); - - /* check if state is changed and reply is received */ - do { - network_read = pico_mock_network_read(mock, buf, BUFLEN); - } while (buf[0] == 0x33); - printf("Received message: %d bytes\n", network_read); - fail_unless(network_read > 0, "received msg on network of %d bytes", network_read); - printbuf(&(buf[0]), (uint32_t)network_read, "DHCP-ACK msg", printbufactive); - fail_unless(buf[0x11c] == 0x05, "No DHCP ACK received after discovery"); -} -END_TEST - - -START_TEST (test_dhcp_server_ipninarp) -{ -/************************************************************************ - * Check if dhcp recv works correctly if - * MAC address of client is not in arp table yet - * Status : Done - *************************************************************************/ - struct mock_device*mock; - struct pico_dhcp_server_setting s = { - 0 - }; - struct pico_ip4 xid = { - .addr = long_be(0x00003d1d) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct pico_ip4 serverip = { - .addr = long_be(0x0A28000A) - }; - struct pico_socket sock = { }; - struct pico_dhcp_server_negotiation *dn = NULL; - struct pico_ip4 *stored_ipv4 = NULL; - unsigned char macaddr1[6] = { - 0xc1, 0, 0, 0xa, 0xb, 0xf - }; - uint32_t len = 0; - uint8_t buf[600] = { - 0 - }; - uint8_t printbufactive = 0; - - printf("*********************** starting %s * \n", __func__); - - /*Insert custom values in buffer*/ - fail_if(generate_dhcp_msg(buf, &len, DHCP_MSG_TYPE_DISCOVER), "DHCP_SERVER->failed to generate buffer"); - memcpy(&(buf[4]), &(xid.addr), sizeof(struct pico_ip4)); - memcpy(&(buf[28]), &(macaddr1[0]), sizeof(struct pico_ip4)); - printbuf(&(buf[0]), len, "DHCP-DISCOVER packet", printbufactive); - - /*Initiate test setup*/ - pico_stack_init(); - - /* Create mock device */ - mock = pico_mock_create(macaddr1); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_mock_network_read(mock, buf, BUFLEN), "data on network that shouldn't be there"); - fail_if(pico_ipv4_link_add(mock->dev, serverip, netmask), "add link to mock device failed"); - s.server_ip = serverip; - - fail_if(pico_dhcp_server_initiate(&s), "DHCP_SERVER> server initiation failed"); - - dn = pico_dhcp_server_find_negotiation(xid.addr); - fail_unless(dn == NULL, "DCHP SERVER -> negotiation data available before discover msg recvd"); - - /* simulate reception of a DISCOVER packet */ - sock.local_addr.ip4 = serverip; - pico_dhcp_server_recv(&sock, buf, len); - - /* check if negotiation data is stored */ - dn = pico_dhcp_server_find_negotiation(xid.addr); - fail_if(dn == NULL, "DCHP SERVER -> no negotiation stored after discover msg recvd"); - - /* check if new ip is in ARP cache */ - stored_ipv4 = pico_arp_reverse_lookup(&dn->hwaddr); - fail_if(stored_ipv4 == NULL, "DCHP SERVER -> new address is not inserted in ARP"); - fail_unless(stored_ipv4->addr == dn->ciaddr.addr, "DCHP SERVER -> new ip not stored in negotiation data"); - - /* check if new ip is in ARP cache */ - fail_if(pico_arp_reverse_lookup(&dn->hwaddr) == NULL, "DCHP SERVER -> new address is not inserted in ARP"); -} -END_TEST - -START_TEST (test_dhcp_server_ipinarp) -{ -/************************************************************************ - * Check if dhcp recv works correctly if - * MAC address of client is allready in arp table - * Status : Done - *************************************************************************/ - struct mock_device*mock; - struct pico_dhcp_server_setting s = { - 0 - }; - struct pico_ip4 ipv4address = { - .addr = long_be(0x0a280067) - }; - struct pico_ip4 xid = { - .addr = long_be(0x00003d1d) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct pico_ip4 serverip = { - .addr = long_be(0x0A28000A) - }; - struct pico_socket sock = { }; - struct pico_ip4 *stored_ipv4 = NULL; - struct pico_dhcp_server_negotiation *dn = NULL; - struct pico_eth *arp_resp = NULL; - unsigned char macaddr1[6] = { - 0xc1, 0, 0, 0xa, 0xb, 0xf - }; - uint32_t len = 0; - uint8_t buf[600] = { - 0 - }; - - printf("*********************** starting %s * \n", __func__); - - /*Insert custom values in buffer*/ - fail_if(generate_dhcp_msg(buf, &len, DHCP_MSG_TYPE_DISCOVER), "DHCP_SERVER->failed to generate buffer"); - memcpy(&(buf[28]), &(macaddr1[0]), sizeof(struct pico_ip4)); - memcpy(&(buf[4]), &(xid.addr), sizeof(struct pico_ip4)); - - /* Create mock device */ - mock = pico_mock_create(macaddr1); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_ipv4_link_add(mock->dev, serverip, netmask), "add link to mock device failed"); - s.server_ip = serverip; - - /*Initiate test setup*/ - pico_stack_init(); - pico_arp_create_entry(&(macaddr1[0]), ipv4address, s.dev); - - fail_if(pico_dhcp_server_initiate(&s), "DHCP_SERVER> server initiation failed"); - - /* simulate reception of a DISCOVER packet */ - sock.local_addr.ip4 = serverip; - pico_dhcp_server_recv(&sock, buf, len); - - /* check if negotiation data is stored */ - dn = pico_dhcp_server_find_negotiation(xid.addr); - fail_if(dn == NULL, "DCHP SERVER -> no negotiation stored after discover msg recvd"); - - /* check if new ip is in ARP cache */ - stored_ipv4 = pico_arp_reverse_lookup(&dn->hwaddr); - fail_if(stored_ipv4 == NULL, "DCHP SERVER -> new address is not inserted in ARP"); - fail_unless(stored_ipv4->addr == dn->ciaddr.addr, "DCHP SERVER -> new ip not stored in negotiation data"); - - /* check if new ip is in ARP cache */ - arp_resp = pico_arp_lookup(&ipv4address); - fail_if(arp_resp == NULL, "DCHP SERVER -> address unavailable in arp cache"); -} -END_TEST - -#if 0 -START_TEST (test_dhcp_client) -{ - struct mock_device*mock; - uint32_t dhcp_hdr_offset = PICO_SIZE_ETHHDR + PICO_SIZE_IP4HDR + PICO_UDPHDR_SIZE; - unsigned char macaddr1[6] = { - 0xc1, 0, 0, 0xa, 0xb, 0xf - }; - struct pico_ip4 address = { - 0 - }; - struct pico_ip4 yiaddr = { - .addr = long_be(0xC0A8000A) - }; - struct pico_ip4 gateway = { - 0 - }; - struct pico_ip4 router = { - .addr = long_be(0xC0A800FE) - }; - uint8_t buf[BUFLEN] = { - 0 - }; - uint8_t offer_buf1[] = { - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8, 0x00, 0x01 - }; - uint8_t offer_buf2[] = { - 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, 0x3a, 0x04, 0x00, 0x00, 0x07, 0x08, 0x3b, 0x04, 0x00, 0x00, 0x0c, 0x4e, 0x33, 0x04, 0x00, 0x00, 0x0e, 0x10, 0x36, 0x04, 0xc0, 0xa8, 0x00, 0x01, 0xff - }; - uint8_t routeropt_buf[] = { - PICO_DHCPOPT_ROUTER, 0x04, 0xC0, 0xA8, 0x00, 0xFE, 0xFF - }; - int type = 0; - uint8_t printbufactive = 0; - uint32_t len = 0; - uint32_t xid = 0; - struct pico_dhcp_client_cookie *cli = NULL; - - pico_stack_init(); - - /* Create mock device */ - mock = pico_mock_create(macaddr1); - fail_if(!mock, "MOCK DEVICE creation failed"); - fail_if(pico_mock_network_read(mock, buf, BUFLEN), "data on network that shouldn't be there"); - - /* initiate negotiation -> change state to */ - pico_dhcp_initiate_negotiation(mock->dev, &callback_dhcpclient, &xid); - cli = get_cookie_by_xid(xid); - dhcp_client_ptr = cli; - fail_if(cli == NULL, "initiate fail"); - fail_unless(cli->state == DHCPSTATE_DISCOVER, "Not in discover state after init negotiate"); - fail_if(pico_mock_network_read(mock, buf, BUFLEN), "data on network that shouldn't be there"); - - /* push discover msg on network */ - tick_it(3); - - /* read discover message from network */ - len = pico_mock_network_read(mock, buf, BUFLEN ); - fail_unless(len, "No msg received on network!"); - printbuf(&(buf[0]), len, "DHCP-DISCOVER packet", printbufactive); - fail_unless(buf[0x011c] == 0x01, "No DHCP Discover received after initiate negotiation"); - mock_print_protocol(buf); - fail_if(pico_mock_network_read(mock, buf, BUFLEN), "data on network that shouldn't be there"); - - /* check API access functions */ - address = pico_dhcp_get_address(cli); - fail_unless(address.addr == 0, "Client address gets value at init -> should get it from dhcp server"); - - gateway = pico_dhcp_get_gateway(cli); - fail_unless(gateway.addr == 0, "Gateway gets value at init -> should get it from dhcp server "); - - /* Change received discovery msg to offer offer msg */ - buf[0x2a] = 0x02; - memcpy(&(buf[0x3a]), &(offer_buf1[0]), sizeof(offer_buf1)); - memcpy(&(buf[0x3a]), &(yiaddr.addr), sizeof(struct pico_ip4)); - memcpy(&(buf[0x116]), &(offer_buf2[0]), sizeof(offer_buf2)); - memcpy(&(buf[0x13b]), &(routeropt_buf[0]), sizeof(routeropt_buf)); - memcpy(&(buf[0x13d]), &(router.addr), sizeof(struct pico_ip4)); - printbuf(&(buf[dhcp_hdr_offset]), len - dhcp_hdr_offset, "DHCP-OFFER message", printbufactive); - - /* generate dhcp type from msg */ - type = pico_dhcp_verify_and_identify_type(&(buf[dhcp_hdr_offset]), len - dhcp_hdr_offset, cli); - fail_if(type == 0, "unkown DHCP type"); - - /* simulate reception of a DHCP server offer */ - pico_dhcp_state_machine(type, cli, &(buf[dhcp_hdr_offset]), len - dhcp_hdr_offset); - fail_if(cli->state == DHCPSTATE_DISCOVER, "still in discover state after dhcp server offer"); - fail_unless(cli->state == DHCPSTATE_REQUEST, "not in REQUEST state after dhcp server offer"); - - address = pico_dhcp_get_address(cli); - fail_unless(address.addr == yiaddr.addr, "Client address incorrect => yiaddr or pico_dhcp_get_address incorrect"); - gateway = pico_dhcp_get_gateway(cli); - fail_unless(gateway.addr == router.addr, "Gateway incorrect! => routeroption or pico_dhcp_get_gateway incorrect"); - tick_it(3); - - len = pico_mock_network_read(mock, buf, BUFLEN); - fail_unless(len, "received msg on network of %d bytes", len); - printbuf(&(buf[0]), len, "DHCP-REQUEST packet", printbufactive); - fail_unless(buf[0x011c] == 0x03, "No DHCP request received after offer"); - -} -END_TEST -#endif - -START_TEST (test_dhcp_client_api) -{ -/************************************************************************ - * Check API of pico_dhcp_initiate_negotiation - * Status : Done - ************************************************************************/ - - /* Declaration test 0 */ - uint32_t xid0 = 0; - struct pico_dhcp_client_cookie *cli0 = NULL; - /* Declaration test 1 */ - uint32_t xid1 = 0; - struct pico_dhcp_client_cookie *cli1 = NULL; - - printf("*********************** starting %s * \n", __func__); - - /* test 0 */ - /* Clear error code */ - pico_err = PICO_ERR_NOERR; - /* Test 0 statements */ - pico_dhcp_initiate_negotiation(NULL, NULL, &xid0); - cli0 = pico_dhcp_client_find_cookie(xid0); - fail_unless(cli0 == NULL, "DHCP_CLIENT> initiate succeeded after pointer to dev == NULL"); - fail_unless(pico_err == PICO_ERR_EINVAL, "DHCP_SERVER> initiate succeeded without PICO_ERR_EINVAL after wrong parameter"); - - /* test 1 */ - /* Clear error code */ - pico_err = PICO_ERR_NOERR; - /* Test 1 statements */ - pico_dhcp_initiate_negotiation(NULL, &callback_dhcpclient, &xid1); - cli1 = pico_dhcp_client_find_cookie(xid1); - fail_unless(cli1 == NULL, "DHCP_CLIENT> initiate succeeded after pointer to dev == NULL"); - fail_unless(pico_err == PICO_ERR_EINVAL, "DHCP_SERVER> initiate succeeded without PICO_ERR_EINVAL after wrong parameter"); - -#if 0 - /* not testable since we do not have a stub for the pico_socket_sendto */ - /* Declaration test 2 */ - uint32_t xid2 = 0; - struct pico_dhcp_client_cookie *cli2 = NULL; - struct pico_device *dev2; - struct mock_device *mock2 = NULL; - - /* test 2 */ - /* Create device */ - dev2 = pico_null_create("dummy"); - mock2 = pico_mock_create(NULL); - fail_if(mock2 == NULL, "No device created"); - /* Clear error code */ - pico_err = PICO_ERR_NOERR; - /* Test 2 statements */ - xid2 = pico_dhcp_initiate_negotiation(dev2, &callback_dhcpclient); - cli2 = get_cookie_by_xid(xid2); - fail_if(cli2 == NULL, "DHCP_CLIENT: error initiating: %s", strerror(pico_err)); - xid2 = pico_dhcp_initiate_negotiation(mock2->dev, &callback_dhcpclient); - cli2 = get_cookie_by_xid(xid2); - fail_if(cli2 == NULL, "DHCP_CLIENT: error initiating: %s", strerror(pico_err)); - xid2 = pico_dhcp_initiate_negotiation(dev2, &callback_dhcpclient); - cli2 = get_cookie_by_xid(xid2); - fail_if(cli2 == NULL, "DHCP_CLIENT: error initiating: %s", strerror(pico_err)); -#endif -} -END_TEST diff --git a/ext/picotcp/test/unit/unit_dns.c b/ext/picotcp/test/unit/unit_dns.c deleted file mode 100644 index 7b3e218..0000000 --- a/ext/picotcp/test/unit/unit_dns.c +++ /dev/null @@ -1,88 +0,0 @@ -void cb_dns(char *ip, void *arg); - -void cb_dns(char *ip, void *arg) -{ - if (!ip) { - /* Error occured */ - printf("DNS error getaddr\n"); - return; - } - - /* Do something */ - printf("DNS -> %s\n", ip); - PICO_FREE(ip); - if (arg) - PICO_FREE(arg); -} - - -START_TEST (test_dns) -{ - int ret; - char url[] = "www.google.com"; - char ip[] = "8.8.4.4"; - struct pico_ip4 ns; - - ns.addr = long_be(0x0a00280a); /* 10.40.0.10 */ - - pico_stack_init(); - - printf("START DNS TEST\n"); - - /* testing nameserver API */ - ret = pico_dns_client_nameserver(NULL, PICO_DNS_NS_ADD); - fail_if(ret == 0, "dns> dns_client_nameserver add error"); - - ret = pico_dns_client_nameserver(NULL, PICO_DNS_NS_DEL); - fail_if(ret == 0, "dns> dns_client_nameserver del error"); - - ret = pico_dns_client_nameserver(NULL, 99); - fail_if(ret == 0, "dns> dns_client_nameserver wrong code"); - - ret = pico_dns_client_nameserver(NULL, 0xFF); - fail_if(ret == 0, "dns> dns_client_nameserver wrong code"); - - ret = pico_dns_client_nameserver(&ns, PICO_DNS_NS_DEL); /* delete non added ns */ - fail_if(ret == 0, "dns> dns_client_nameserver del error"); - - ret = pico_dns_client_nameserver(&ns, 99); - fail_if(ret == 0, "dns> dns_client_nameserver wrong code"); - - ret = pico_dns_client_nameserver(&ns, PICO_DNS_NS_ADD); /* add correct one */ - fail_if(ret < 0, "dns> dns_client_nameserver add error: %s", strerror(pico_err)); - - ret = pico_dns_client_nameserver(&ns, 99); - fail_if(ret == 0, "dns> dns_client_nameserver wrong code"); - - ret = pico_dns_client_nameserver(&ns, PICO_DNS_NS_DEL); - fail_if(ret < 0, "dns> dns_client_nameserver del error: %s", strerror(pico_err)); - - ret = pico_dns_client_nameserver(&ns, PICO_DNS_NS_ADD); /* add correct one */ - fail_if(ret < 0, "dns> dns_client_nameserver add error: %s", strerror(pico_err)); - - ret = pico_dns_client_nameserver(&ns, PICO_DNS_NS_ADD); /* add correct one again */ - fail_if(ret < 0, "dns> dns_client_nameserver add double failed"); - - /* testing getaddr API */ - /* not testable since we do not have a stub for the pico_socket_send */ - /* ret = pico_dns_client_getaddr(url, cb_dns, NULL); / * ask correct one * / */ - /* fail_if(ret < 0, "dns> dns_client_getaddr: %s",strerror(pico_err)); */ - - ret = pico_dns_client_getaddr(NULL, cb_dns, NULL); - fail_if(ret == 0, "dns> dns_client_getaddr: no url"); - - ret = pico_dns_client_getaddr(url, NULL, NULL); - fail_if(ret == 0, "dns> dns_client_getaddr: no cb"); - - /* testing getname API */ - /* not testable since we do not have a stub for the pico_socket_send */ - /* ret = pico_dns_client_getname(ip, cb_dns, NULL); / * ask correct one * / */ - /* fail_if(ret < 0, "dns> dns_client_getname: %s",strerror(pico_err)); */ - - ret = pico_dns_client_getname(NULL, cb_dns, NULL); - fail_if(ret == 0, "dns> dns_client_getname: no ip"); - - ret = pico_dns_client_getname(ip, NULL, NULL); - fail_if(ret == 0, "dns> dns_client_getname: no cb"); -} -END_TEST diff --git a/ext/picotcp/test/unit/unit_icmp4.c b/ext/picotcp/test/unit/unit_icmp4.c deleted file mode 100644 index 086a41c..0000000 --- a/ext/picotcp/test/unit/unit_icmp4.c +++ /dev/null @@ -1,401 +0,0 @@ - -#include "pico_icmp4.h" -#define NUM_PING 1 -int ping_test_var = 0; - -void cb_ping(struct pico_icmp4_stats *s); -void icmp4_unreach_socket_cb(uint16_t ev, struct pico_socket *s); - -void cb_ping(struct pico_icmp4_stats *s) -{ - char host[30]; - pico_ipv4_to_string(host, s->dst.addr); - if (s->err == 0) { - dbg("%lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", s->size, host, s->seq, s->time); - if (s->seq == NUM_PING) { - ping_test_var++; - } - - fail_if (s->seq > NUM_PING); - } else { - dbg("PING %lu to %s: Error %d\n", s->seq, host, s->err); - exit(1); - } -} - -START_TEST (test_icmp4_ping) -{ - struct pico_ip4 local = { - 0 - }; - struct pico_ip4 remote = { - 0 - }; - struct pico_ip4 netmask = { - 0 - }; - struct mock_device *mock = NULL; - char local_address[] = { - "192.168.1.102" - }; - char remote_address[] = { - "192.168.1.103" - }; - uint16_t interval = 1000; - uint16_t timeout = 5000; - uint8_t size = 48; - - int bufferlen = 80; - uint8_t buffer[bufferlen]; - int len; - uint8_t temp_buf[4]; - printf("*********************** starting %s * \n", __func__); - - pico_string_to_ipv4(local_address, &(local.addr)); - pico_string_to_ipv4("255.255.255.0", &(netmask.addr)); - - pico_string_to_ipv4(remote_address, &(remote.addr)); - pico_string_to_ipv4("255.255.255.0", &(netmask.addr)); - - pico_stack_init(); - - mock = pico_mock_create(NULL); - fail_if(mock == NULL, "No device created"); - - pico_ipv4_link_add(mock->dev, local, netmask); - - fail_if(pico_icmp4_ping(local_address, NUM_PING, interval, timeout, size, cb_ping) < 0); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - fail_if(ping_test_var != 1); - - pico_icmp4_ping(remote_address, NUM_PING, interval, timeout, size, cb_ping); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - /* get the packet from the mock_device */ - memset(buffer, 0, (size_t)bufferlen); - len = pico_mock_network_read(mock, buffer, bufferlen); - fail_if(len < 20); - /* inspect it */ - fail_unless(mock_ip_protocol(mock, buffer, len) == 1); - fail_unless(mock_icmp_type(mock, buffer, len) == 8); - fail_unless(mock_icmp_code(mock, buffer, len) == 0); - fail_unless(pico_checksum(buffer + 20, (uint32_t)(len - 20)) == 0); - - /* cobble up a reply */ - buffer[20] = 0; /* type 0 : reply */ - memcpy(temp_buf, buffer + 12, 4); - memcpy(buffer + 12, buffer + 16, 4); - memcpy(buffer + 16, temp_buf, 4); - - /* using the mock-device because otherwise I have to put everything in a pico_frame correctly myself. */ - pico_mock_network_write(mock, buffer, len); - /* check if it is received */ - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - fail_unless(ping_test_var == 2); - - /* repeat but make it an invalid reply... */ - - pico_icmp4_ping(remote_address, NUM_PING, interval, timeout, size, cb_ping); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - /* get the packet from the mock_device */ - memset(buffer, 0, (size_t)bufferlen); - len = pico_mock_network_read(mock, buffer, bufferlen); - /* inspect it */ - fail_unless(mock_ip_protocol(mock, buffer, len) == 1); - fail_unless(mock_icmp_type(mock, buffer, len) == 8); - fail_unless(mock_icmp_code(mock, buffer, len) == 0); - fail_unless(pico_checksum(buffer + 20, (uint32_t)(len - 20)) == 0); - - /* cobble up a reply */ - buffer[20] = 0; /* type 0 : reply */ - memcpy(temp_buf, buffer + 12, 4); - memcpy(buffer + 12, buffer + 16, 4); - memcpy(buffer + 16, temp_buf, 4); - buffer[26] = (uint8_t)~buffer[26]; /* flip some bits in the sequence number, to see if the packet gets ignored properly */ - - /* using the mock-device because otherwise I have to put everything in a pico_frame correctly myself. */ - pico_mock_network_write(mock, buffer, len); - /* check if it is received */ - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - fail_unless(ping_test_var == 2); -} -END_TEST - - -START_TEST (test_icmp4_incoming_ping) -{ - int bufferlen = 76; - uint8_t buffer[76] = { - 0x45, 0x00, 0x00, 0x4c, - 0x91, 0xc3, 0x40, 0x00, - 0x40, 0x01, 0x24, 0xd0, - 0xc0, 0xa8, 0x01, 0x66, - 0xc0, 0xa8, 0x01, 0x64, - 0x08, 0x00, 0x66, 0x3c, - 0x91, 0xc2, 0x01, 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, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - int buffer2len = 76; - int len; - int cntr = 0; - uint8_t buffer2[bufferlen]; - struct pico_ip4 local = { - .addr = long_be(0xc0a80164) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct mock_device*mock; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) buffer; - printf("*********************** starting %s * \n", __func__); - - pico_stack_init(); - - mock = pico_mock_create(NULL); - fail_if(mock == NULL, "No device created"); - - pico_ipv4_link_add(mock->dev, local, netmask); - - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, PICO_SIZE_IP4HDR)); - pico_mock_network_write(mock, buffer, bufferlen); - /* check if it is received */ - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - - len = pico_mock_network_read(mock, buffer2, buffer2len); - /* inspect it */ - - while(cntr < len) { - printf("0x%02x ", buffer2[cntr]); - cntr++; - if(cntr % 4 == 0) - printf("\n"); - } - fail_unless(len == buffer2len, "ping reply lenght does not match, expected len: %d, got: %d", buffer2len, len); - fail_unless(mock_ip_protocol(mock, buffer2, len) == 1); - fail_unless(mock_icmp_type(mock, buffer2, len) == 0); - fail_unless(mock_icmp_code(mock, buffer2, len) == 0); - fail_unless(pico_checksum(buffer2 + 20, (uint32_t)(len - 20)) == 0); - -} -END_TEST - -START_TEST (test_icmp4_unreachable_send) -{ - struct pico_ip4 local = { - .addr = long_be(0x0a280064) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct mock_device*mock; - int len = 0; - int bufferlen = 80; - uint8_t buffer2[bufferlen]; - - uint8_t buffer[32] = { - 0x45, 0x00, 0x00, 0x20, 0x91, 0xc0, 0x40, 0x00, - 0x40, 0x11, 0x94, 0xb4, 0x0a, 0x28, 0x00, 0x05, - 0x0a, 0x28, 0x00, 0x04, 0x15, 0xb3, 0x15, 0xb3, - 0x00, 0x0c, 0x00, 0x00, 'e', 'l', 'l', 'o' - }; - - /* fake packet with bad upper-layer-protocol */ - uint8_t buffer3[20] = { - 0x45, 0x00, 0x00, 0x14, 0x91, 0xc0, 0x40, 0x00, - 0x40, 0xff, 0x94, 0xb4, 0x0a, 0x28, 0x00, 0x05, - 0x0a, 0x28, 0x00, 0x04 - }; - - struct pico_frame*f = PICO_ZALLOC(sizeof(struct pico_frame)); - printf("*********************** starting %s * \n", __func__); - - f->net_hdr = buffer; - f->buffer = buffer; - - pico_stack_init(); - - mock = pico_mock_create(NULL); - fail_if(mock == NULL, "No device created"); - - pico_ipv4_link_add(mock->dev, local, netmask); - - - fail_if(pico_icmp4_dest_unreachable(f)); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - len = pico_mock_network_read(mock, buffer2, bufferlen); - - fail_unless(len == 56, "len is indeed %d\n", len); - fail_unless(mock_ip_protocol(mock, buffer2, len) == 1); - fail_unless(mock_icmp_type(mock, buffer2, len) == 3); /* destination unreachable */ - fail_unless(mock_icmp_code(mock, buffer2, len) == 1); /* host unreachable */ - fail_unless(pico_checksum(buffer2 + 20, (uint32_t)(len - 20)) == 0); - - - fail_if(pico_icmp4_port_unreachable(f)); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - len = pico_mock_network_read(mock, buffer2, bufferlen); - - fail_unless(len == 56); - fail_unless(mock_ip_protocol(mock, buffer2, len) == 1); - fail_unless(mock_icmp_type(mock, buffer2, len) == 3); /* destination unreachable */ - fail_unless(mock_icmp_code(mock, buffer2, len) == 3); /* port unreachable */ - fail_unless(pico_checksum(buffer2 + 20, (uint32_t)(len - 20)) == 0); - - - fail_if(pico_icmp4_proto_unreachable(f)); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - len = pico_mock_network_read(mock, buffer2, bufferlen); - - fail_unless(len == 56); - fail_unless(mock_ip_protocol(mock, buffer2, len) == 1); - fail_unless(mock_icmp_type(mock, buffer2, len) == 3); /* destination unreachable */ - fail_unless(mock_icmp_code(mock, buffer2, len) == 2); /* proto unreachable */ - fail_unless(pico_checksum(buffer2 + 20, (uint32_t)(len - 20)) == 0); - - - fail_if(pico_icmp4_ttl_expired(f)); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - len = pico_mock_network_read(mock, buffer2, bufferlen); - - fail_unless(len == 56); - fail_unless(mock_ip_protocol(mock, buffer2, len) == 1); - fail_unless(mock_icmp_type(mock, buffer2, len) == 11); /* ttl expired */ - fail_unless(mock_icmp_code(mock, buffer2, len) == 0); - fail_unless(pico_checksum(buffer2 + 20, (uint32_t)(len - 20)) == 0); - - f->net_hdr = buffer3; - f->buffer = buffer3; - - fail_if(pico_icmp4_proto_unreachable(f)); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - - len = pico_mock_network_read(mock, buffer2, bufferlen); - - fail_unless(len == 48); /* Buffer 3 is shorter, reply is shorter too... */ - fail_unless(mock_ip_protocol(mock, buffer2, len) == 1); - fail_unless(mock_icmp_type(mock, buffer2, len) == 3); /* destination unreachable */ - fail_unless(mock_icmp_code(mock, buffer2, len) == 2); /* proto unreachable */ - fail_unless(pico_checksum(buffer2 + 20, (uint32_t)(len - 20)) == 0); -} -END_TEST - -int icmp4_socket_unreach_status = 0; -void icmp4_unreach_socket_cb(uint16_t ev, struct pico_socket *s) -{ - IGNORE_PARAMETER(s); - - if (ev == PICO_SOCK_EV_ERR) { - icmp4_socket_unreach_status = 1; - } -} - -START_TEST (test_icmp4_unreachable_recv) -{ - struct pico_ip4 local = { - .addr = long_be(0x0a280064) - }; - struct pico_ip4 remote = { - .addr = long_be(0x0a280065) - }; - struct pico_ip4 netmask = { - .addr = long_be(0xffffff00) - }; - struct mock_device*mock; - struct pico_socket*sock; - uint16_t port = short_be(7777); - - /* put a host unreachable in the queue, run a few stack ticks */ - uint8_t buffer[] = { - 0x45, 0x00, 0x00, 0x20, - 0x91, 0xc0, 0x40, 0x00, - 0x40, 0x01, 0x94, 0xb4, - 0x0a, 0x28, 0x00, 0x65, - 0x0a, 0x28, 0x00, 0x64, - 0x03, 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, 0x00, 0x00, - }; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) buffer; - - printf("*********************** starting %s * \n", __func__); - pico_stack_init(); - - mock = pico_mock_create(NULL); - fail_if(mock == NULL, "No device created"); - - pico_ipv4_link_add(mock->dev, local, netmask); - - /* open a socket */ - sock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &icmp4_unreach_socket_cb); - fail_if(sock == NULL); - fail_if(pico_socket_bind(sock, &local, &port)); - pico_socket_connect(sock, &remote, port); - pico_socket_write(sock, "fooo", 4); - /* see if my callback was called with the proper code */ - - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - /* filling in the IP header and first 8 bytes */ - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, PICO_SIZE_IP4HDR)); - printf("read %d bytes\n", pico_mock_network_read(mock, buffer + 28, 28)); - - printf("wrote %d bytes\n", pico_mock_network_write(mock, buffer, 56)); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - fail_unless(icmp4_socket_unreach_status == 1); -} -END_TEST diff --git a/ext/picotcp/test/unit/unit_ipv4.c b/ext/picotcp/test/unit/unit_ipv4.c deleted file mode 100644 index a708688..0000000 --- a/ext/picotcp/test/unit/unit_ipv4.c +++ /dev/null @@ -1,852 +0,0 @@ - -START_TEST (test_ipv4) -{ - #define IP_TST_SIZ 256 - uint32_t i; - - struct pico_device *dev[IP_TST_SIZ]; - char devname[8]; - struct pico_ip4 a[IP_TST_SIZ], d[IP_TST_SIZ], *source[IP_TST_SIZ], nm16, nm32, gw[IP_TST_SIZ], r[IP_TST_SIZ], ret; - struct pico_ipv4_link *l[IP_TST_SIZ]; - - char ipstr[] = "192.168.1.1"; - struct pico_ip4 ipaddr; - - struct pico_frame *f_NULL = NULL; - struct pico_ip4 *dst_NULL = NULL; - - pico_stack_init(); - - nm16.addr = long_be(0xFFFF0000); - nm32.addr = long_be(0xFFFFFFFF); - - /*link_add*/ - for (i = 0; i < IP_TST_SIZ; i++) { - snprintf(devname, 8, "nul%d", i); - dev[i] = pico_null_create(devname); - a[i].addr = long_be(0x0a000001u + (i << 16)); - d[i].addr = long_be(0x0a000002u + (i << 16)); - fail_if(pico_ipv4_link_add(dev[i], a[i], nm16) != 0, "Error adding link"); - } - /*link_find + link_get + route_add*/ - for (i = 0; i < IP_TST_SIZ; i++) { - gw[i].addr = long_be(0x0a0000f0u + (i << 16)); - r[i].addr = long_be(0x0c00001u + (i << 16)); - fail_unless(pico_ipv4_link_find(&a[i]) == dev[i], "Error finding link"); - l[i] = pico_ipv4_link_get(&a[i]); - fail_if(l[i] == NULL, "Error getting link"); - fail_if(pico_ipv4_route_add(r[i], nm32, gw[i], 1, l[i]) != 0, "Error adding route"); - fail_if(pico_ipv4_route_add(d[i], nm32, gw[i], 1, l[i]) != 0, "Error adding route"); - } - /*get_gateway + source_find*/ - for (i = 0; i < IP_TST_SIZ; i++) { - ret = pico_ipv4_route_get_gateway(&r[i]); - fail_if(ret.addr != gw[i].addr, "Error get gateway: returned wrong route"); - source[i] = pico_ipv4_source_find(&d[i]); - fail_if(source[i]->addr != a[i].addr, "Error find source: returned wrong route"); - } - /*route_del + link_del*/ - for (i = 0; i < IP_TST_SIZ; i++) { - fail_if(pico_ipv4_route_del(r[i], nm32, 1) != 0, "Error deleting route"); - fail_if(pico_ipv4_link_del(dev[i], a[i]) != 0, "Error deleting link"); - } - /*string_to_ipv4 + ipv4_to_string*/ - pico_string_to_ipv4(ipstr, &(ipaddr.addr)); - fail_if(ipaddr.addr != long_be(0xc0a80101), "Error string to ipv4"); - memset(ipstr, 0, 12); - pico_ipv4_to_string(ipstr, ipaddr.addr); - fail_if(strncmp(ipstr, "192.168.1.1", 11) != 0, "Error ipv4 to string"); - - /*valid_netmask*/ - fail_if(pico_ipv4_valid_netmask(long_be(nm32.addr)) != 32, "Error checking netmask"); - - /*is_unicast*/ - fail_if((pico_ipv4_is_unicast(long_be(0xc0a80101))) != 1, "Error checking unicast"); - fail_if((pico_ipv4_is_unicast(long_be(0xe0000001))) != 0, "Error checking unicast"); - - /*rebound*/ - fail_if(pico_ipv4_rebound(f_NULL) != -1, "Error rebound frame"); - - /*frame_push*/ - fail_if(pico_ipv4_frame_push(f_NULL, dst_NULL, PICO_PROTO_TCP) != -1, "Error push frame"); -} -END_TEST - -START_TEST (test_nat_enable_disable) -{ - struct pico_ipv4_link link = { - .address = {.addr = long_be(0x0a320001)} - }; /* 10.50.0.1 */ - struct pico_frame *f = pico_ipv4_alloc(&pico_proto_ipv4, NULL, PICO_UDPHDR_SIZE); - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr; - const char *raw_data = "ello"; - - net->vhl = 0x45; /* version = 4, hdr len = 5 (32-bit words) */ - net->tos = 0; - net->len = short_be(32); /* hdr + data (bytes) */ - net->id = short_be(0x91c0); - net->frag = short_be(0x4000); /* don't fragment flag, offset = 0 */ - net->ttl = 64; - net->proto = 17; /* UDP */ - net->crc = 0; - net->src.addr = long_be(0x0a280008); /* 10.40.0.8 */ - net->dst.addr = long_be(0x0a320001); /* 10.50.0.1 */ - - udp->trans.sport = short_be(5555); - udp->trans.dport = short_be(6667); - udp->len = 12; - udp->crc = 0; - - f->payload = f->transport_hdr + PICO_UDPHDR_SIZE; - memcpy(f->payload, raw_data, 4); - - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> NAT ENABLE/DISABLE TEST\n"); - pico_stack_init(); - - fail_if(pico_ipv4_nat_enable(&link)); - fail_unless(nat_link->address.addr == link.address.addr); - fail_unless(pico_ipv4_nat_is_enabled(&link.address)); - - fail_if(pico_ipv4_nat_outbound(f, &net->dst)); - pico_ipv4_nat_table_cleanup(pico_tick, NULL); - - fail_if(pico_ipv4_nat_disable()); - fail_if(pico_ipv4_nat_is_enabled(&link.address)); -} -END_TEST - -START_TEST (test_nat_translation) -{ - struct pico_ipv4_link link = { - .address = {.addr = long_be(0x0a320001)} - }; /* 10.50.0.1 */ - struct pico_frame *f = pico_ipv4_alloc(&pico_proto_ipv4, NULL, PICO_UDPHDR_SIZE); - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr; - struct pico_ip4 src_ori = { - .addr = long_be(0x0a280008) - }; /* 10.40.0.8 */ - struct pico_ip4 dst_ori = { - .addr = long_be(0x0a320009) - }; /* 10.50.0.9 */ - struct pico_ip4 nat = { - .addr = long_be(0x0a320001) - }; /* 10.50.0.9 */ - const char *raw_data = "ello"; - uint16_t sport_ori = short_be(5555); - uint16_t dport_ori = short_be(6667); - uint16_t nat_port = 0; - - net->vhl = 0x45; /* version = 4, hdr len = 5 (32-bit words) */ - net->tos = 0; - net->len = short_be(32); /* hdr + data (bytes) */ - net->id = short_be(0x91c0); - net->frag = short_be(0x4000); /* don't fragment flag, offset = 0 */ - net->ttl = 64; - net->proto = 17; /* UDP */ - net->crc = 0; - net->src = src_ori; - net->dst = dst_ori; - - udp->trans.sport = sport_ori; - udp->trans.dport = dport_ori; - udp->len = 12; - udp->crc = 0; - - f->payload = f->transport_hdr + PICO_UDPHDR_SIZE; - memcpy(f->payload, raw_data, 4); - - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> NAT TRANSLATION TEST\n"); - pico_stack_init(); - fail_if(pico_ipv4_nat_enable(&link)); - - /* perform outbound translation, check if source IP got translated */ - fail_if(pico_ipv4_nat_outbound(f, &nat_link->address)); - fail_if(net->src.addr != link.address.addr, "source address not translated"); - - /* perform outbound translation of same packet, check if source IP and PORT got translated the same as previous packet */ - nat_port = udp->trans.sport; - net->src = src_ori; /* restore original src */ - udp->trans.sport = sport_ori; /* restore original sport */ - fail_if(pico_ipv4_nat_outbound(f, &nat_link->address)); - fail_if(net->src.addr != link.address.addr, "source address not translated"); - fail_if(udp->trans.sport != nat_port, "frames with the same source IP, source PORT and PROTO did not get translated the same"); - - /* perform outbound translation of packet with changed source PORT, check if source PORT got translated differently as previous packet */ - nat_port = udp->trans.sport; - net->src = src_ori; /* restore original src */ - udp->trans.sport = short_be(5556); /* change sport */ - fail_if(pico_ipv4_nat_outbound(f, &nat_link->address)); - fail_if(net->src.addr != link.address.addr, "source address not translated"); - fail_if(udp->trans.sport == short_be(sport_ori), "two frames with different sport get translated the same"); - - /* perform inbound translation of previous packet, check if destination IP and PORT got translated to the original source IP and PORT */ - nat_port = udp->trans.sport; - net->src = dst_ori; - net->dst = nat; - udp->trans.sport = sport_ori; - udp->trans.dport = nat_port; - fail_if(pico_ipv4_nat_inbound(f, &nat_link->address)); - fail_if(net->dst.addr != src_ori.addr, "destination address not translated correctly"); - fail_if(udp->trans.dport != short_be(5556), "ports not translated correctly"); - pico_ipv4_nat_table_cleanup(pico_tick, NULL); - - fail_if(pico_ipv4_nat_disable()); -} -END_TEST - -START_TEST (test_nat_port_forwarding) -{ - struct pico_ipv4_link link = { - .address = {.addr = long_be(0x0a320001)} - }; /* 10.50.0.1 */ - struct pico_frame *f = pico_ipv4_alloc(&pico_proto_ipv4, NULL, PICO_UDPHDR_SIZE); - struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr; - struct pico_ip4 src_addr = { - .addr = long_be(0x0a280008) - }; /* 10.40.0.8 */ - struct pico_ip4 dst_addr = { - .addr = long_be(0x0a320009) - }; /* 10.50.0.9 */ - struct pico_ip4 nat_addr = { - .addr = long_be(0x0a320001) - }; /* 10.50.0.9 */ - const char *raw_data = "ello"; - uint16_t sport_ori = short_be(5555); - uint16_t fport_pub = short_be(80); - uint16_t fport_priv = short_be(8080); - - net->vhl = 0x45; /* version = 4, hdr len = 5 (32-bit words) */ - net->tos = 0; - net->len = short_be(32); /* hdr + data (bytes) */ - net->id = short_be(0x91c0); - net->frag = short_be(0x4000); /* don't fragment flag, offset = 0 */ - net->ttl = 64; - net->proto = 17; /* UDP */ - net->crc = 0; - net->src = dst_addr; - net->dst = nat_addr; - - udp->trans.sport = sport_ori; - udp->trans.dport = fport_pub; - udp->len = 12; - udp->crc = 0; - - f->payload = f->transport_hdr + PICO_UDPHDR_SIZE; - memcpy(f->payload, raw_data, 4); - - printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> NAT PORT FORWARD TEST\n"); - pico_stack_init(); - fail_if(pico_ipv4_nat_enable(&link)); - - fail_if(pico_ipv4_port_forward(nat_addr, fport_pub, src_addr, fport_priv, 17, PICO_NAT_PORT_FORWARD_ADD)); - - fail_if(pico_ipv4_nat_inbound(f, &nat_link->address)); - fail_if(net->dst.addr != src_addr.addr, "destination address not translated correctly"); - fail_if(udp->trans.dport != fport_priv, "destination port not translated correctly"); - - fail_if(pico_ipv4_port_forward(nat_addr, fport_pub, src_addr, fport_priv, 17, PICO_NAT_PORT_FORWARD_DEL)); - pico_ipv4_nat_table_cleanup(pico_tick, NULL); -} -END_TEST - -START_TEST (test_ipfilter) -{ - struct pico_device *dev = NULL; - uint8_t proto = 0, tos = 0; - uint16_t sport = 0, dport = 0; - int8_t priority = 0; - int ret = 0; - - struct pico_ip4 src_addr = { - 0 - }; - struct pico_ip4 saddr_netmask = { - 0 - }; - struct pico_ip4 dst_addr = { - 0 - }; - struct pico_ip4 daddr_netmask = { - 0 - }; - - enum filter_action action = 1; - - uint32_t filter_id1; - - /* 192.168.1.2:16415 -> 192.168.1.109:1222 [sending a TCP syn] */ - uint8_t ipv4_buf[] = { - 0x00, 0x02, 0xf7, 0xf1, 0x79, 0x33, 0xe0, 0xdb, 0x55, - 0xd4, 0xb6, 0x27, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, - 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf7, 0x0f, 0xc0, - 0xa8, 0x01, 0x02, 0xc0, 0xa8, 0x01, 0x6d, 0x40, 0x1f, - 0x04, 0xc6, 0x00, 0xb1, 0x56, 0x5a, 0x00, 0x00, 0x00, - 0x00, 0x50, 0x02, 0x20, 0x00, 0x70, 0x32, 0x00, 0x00 - }; - - struct pico_frame *f; - - printf("IP Filter> Adding a new filter...\n"); - filter_id1 = pico_ipv4_filter_add(dev, proto, &src_addr, &saddr_netmask, &dst_addr, &daddr_netmask, sport, dport, priority, tos, action); - fail_if(filter_id1 <= 0, "Error adding filter\n"); - printf("filter_id1 = %d\n", filter_id1); - - printf("IP Filter> Trying to add the same filter...\n"); - filter_id1 = pico_ipv4_filter_add(dev, proto, &src_addr, &saddr_netmask, &dst_addr, &daddr_netmask, sport, dport, priority, tos, action); - fail_if(ret > 0, "Error adding filter\n"); - - printf("IP Filter> Deleting added filter...\n"); - ret = pico_ipv4_filter_del(filter_id1); - fail_if(ret != 0, "Error deleting the filter\n"); - - printf("IP Filter> Trying to delete the same filter\n"); - ret = pico_ipv4_filter_del(filter_id1); - fail_if(ret != -1, "Deleting non existing filter failed\n"); - - f = (struct pico_frame *)PICO_ZALLOC(200); - f->buffer = PICO_ZALLOC(20); - f->usage_count = PICO_ZALLOC(sizeof(uint32_t)); - f->buffer = ipv4_buf; - f->net_hdr = ipv4_buf + 14u; /* shifting to IP layer */ - f->transport_hdr = ipv4_buf + 34u; /* shifting to Transport layer */ - - /* adding exact filter */ - pico_string_to_ipv4("192.168.1.109", &src_addr.addr); - pico_string_to_ipv4("255.255.255.255", &saddr_netmask.addr); - sport = 1222u; - filter_id1 = pico_ipv4_filter_add(dev, proto, &src_addr, &saddr_netmask, &dst_addr, &daddr_netmask, sport, dport, priority, tos, FILTER_REJECT); - fail_if(filter_id1 <= 0, "Error adding exact filter\n"); - printf("Filter is added\n"); - sync(); - sleep(1); - - ret = ipfilter(f); - fail_if(ret != 1, "Frame wasn't filtered\n"); - - printf("IP Filter> Deleting added filter...\n"); - ret = pico_ipv4_filter_del(filter_id1); - fail_if(ret != 0, "Error deleting the filter\n"); - - printf("IP Filter> Adding masked filter...\n"); - pico_string_to_ipv4("192.168.1.7", &src_addr.addr); - pico_string_to_ipv4("255.255.255.0", &saddr_netmask.addr); - sport = 1222u; - - filter_id1 = pico_ipv4_filter_add(dev, proto, &src_addr, &saddr_netmask, &dst_addr, &daddr_netmask, sport, dport, priority, tos, FILTER_DROP); - fail_if(filter_id1 <= 0, "Error adding masked filter\n"); - - f = (struct pico_frame *)PICO_ZALLOC(200); - f->buffer = PICO_ZALLOC(20); - f->usage_count = PICO_ZALLOC(sizeof(uint32_t)); - f->buffer = ipv4_buf; - f->net_hdr = ipv4_buf + 14u; /* shifting to IP layer */ - f->transport_hdr = ipv4_buf + 34u; /* shifting to Transport layer */ - ret = ipfilter(f); - fail_if(ret != 1, "Mask filter failed to filter\n"); - - printf("IP Filter> Deleting added filter...\n"); - ret = pico_ipv4_filter_del(filter_id1); - fail_if(ret != 0, "Error deleting the filter\n"); - - printf("IP Filter> Adding bad filter..\n"); - pico_string_to_ipv4("191.1.1.7", &src_addr.addr); - pico_string_to_ipv4("255.255.255.0", &saddr_netmask.addr); - sport = 1991u; - filter_id1 = pico_ipv4_filter_add(dev, proto, &src_addr, &saddr_netmask, &dst_addr, &daddr_netmask, sport, dport, priority, tos, FILTER_DROP); - fail_if(filter_id1 <= 0, "Error adding bad filter\n"); - - f = (struct pico_frame *)PICO_ZALLOC(200); - f->buffer = PICO_ZALLOC(20); - f->usage_count = PICO_ZALLOC(sizeof(uint32_t)); - f->buffer = ipv4_buf; - f->net_hdr = ipv4_buf + 14u; /* shifting to IP layer */ - f->transport_hdr = ipv4_buf + 34u; /* shifting to Transport layer */ - ret = ipfilter(f); - fail_if(ret != 0, "Filter shouldn't have filtered this frame\n"); - - printf("IP Filter> Deleting added filter...\n"); - ret = pico_ipv4_filter_del(filter_id1); - fail_if(ret != 0, "Error deleting the filter\n"); - -} -END_TEST - -#ifdef PICO_SUPPORT_MCAST -START_TEST (test_igmp_sockopts) -{ - int i = 0, j = 0, k = 0, ret = 0; - struct pico_socket *s, *s1 = NULL; - struct pico_device *dev = NULL; - union pico_address *source = NULL; - union pico_address inaddr_dst = { - 0 - }, inaddr_incorrect = { - 0 - }, inaddr_uni = { - 0 - }, inaddr_null = { - 0 - }, netmask = { - 0 - }; - union pico_address inaddr_link[2] = {0}; - union pico_address inaddr_mcast[8] = {0}; - union pico_address inaddr_source[8] = {0}; - struct pico_ip_mreq _mreq = {0}, mreq[16] = {0}; - struct pico_ip_mreq_source mreq_source[128] = {0}; - struct pico_tree_node *index = NULL; - - int ttl = 64; - int getttl = 0; - int loop = 9; - int getloop = 0; - union pico_address mcast_def_link = { - 0 - }; - - pico_stack_init(); - - printf("START IGMP SOCKOPTS TEST\n"); - - pico_string_to_ipv4("224.7.7.7", &inaddr_dst.ip4.addr); - pico_string_to_ipv4("10.40.0.2", &inaddr_uni.ip4.addr); - pico_string_to_ipv4("224.8.8.8", &inaddr_incorrect.ip4.addr); - pico_string_to_ipv4("0.0.0.0", &inaddr_null.ip4.addr); - - pico_string_to_ipv4("10.40.0.1", &inaddr_link[0].ip4.addr); /* 0 */ - pico_string_to_ipv4("10.50.0.1", &inaddr_link[1].ip4.addr); /* 1 */ - - pico_string_to_ipv4("232.1.1.0", &inaddr_mcast[0].ip4.addr); /* 0 */ - pico_string_to_ipv4("232.2.2.1", &inaddr_mcast[1].ip4.addr); /* 1 */ - pico_string_to_ipv4("232.3.3.2", &inaddr_mcast[2].ip4.addr); /* 2 */ - pico_string_to_ipv4("232.4.4.3", &inaddr_mcast[3].ip4.addr); /* 3 */ - pico_string_to_ipv4("232.5.5.4", &inaddr_mcast[4].ip4.addr); /* 4 */ - pico_string_to_ipv4("232.6.6.5", &inaddr_mcast[5].ip4.addr); /* 5 */ - pico_string_to_ipv4("232.7.7.6", &inaddr_mcast[6].ip4.addr); /* 6 */ - pico_string_to_ipv4("232.8.8.7", &inaddr_mcast[7].ip4.addr); /* 7 */ - - pico_string_to_ipv4("10.40.1.0", &inaddr_source[0].ip4.addr); /* 0 */ - pico_string_to_ipv4("10.40.1.1", &inaddr_source[1].ip4.addr); /* 1 */ - pico_string_to_ipv4("10.40.1.2", &inaddr_source[2].ip4.addr); /* 2 */ - pico_string_to_ipv4("10.40.1.3", &inaddr_source[3].ip4.addr); /* 3 */ - pico_string_to_ipv4("10.40.1.4", &inaddr_source[4].ip4.addr); /* 4 */ - pico_string_to_ipv4("10.40.1.5", &inaddr_source[5].ip4.addr); /* 5 */ - pico_string_to_ipv4("10.40.1.6", &inaddr_source[6].ip4.addr); /* 6 */ - pico_string_to_ipv4("10.40.1.7", &inaddr_source[7].ip4.addr); /* 7 */ - - /* 00 01 02 03 04 05 06 07 | 10 11 12 13 14 15 16 17 */ - for (i = 0; i < 16; i++) { - mreq[i].mcast_link_addr = inaddr_link[i / 8]; - mreq[i].mcast_group_addr = inaddr_mcast[i % 8]; - } - /* 000 001 002 003 004 005 006 007 | 010 011 012 013 014 015 016 017 */ - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - /* printf(">>>>> mreq_source[%d]: link[%d] mcast[%d] source[%d]\n", (i*8)+j, i/8, i%8, j); */ - mreq_source[(i * 8) + j].mcast_link_addr = inaddr_link[i / 8]; - mreq_source[(i * 8) + j].mcast_group_addr = inaddr_mcast[i % 8]; - mreq_source[(i * 8) + j].mcast_source_addr = inaddr_source[j]; - } - } - dev = pico_null_create("dummy0"); - netmask.ip4.addr = long_be(0xFFFF0000); - ret = pico_ipv4_link_add(dev, inaddr_link[0].ip4, netmask.ip4); - fail_if(ret < 0, "link add failed"); - - dev = pico_null_create("dummy1"); - netmask.ip4.addr = long_be(0xFFFF0000); - ret = pico_ipv4_link_add(dev, inaddr_link[1].ip4, netmask.ip4); - fail_if(ret < 0, "link add failed"); - - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, NULL); - fail_if(s == NULL, "UDP socket open failed"); - s1 = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, NULL); - fail_if(s1 == NULL, "UDP socket open failed"); - - /* argument validation tests */ - printf("IGMP SETOPTION ARGUMENT VALIDATION TEST\n"); - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_IF, &mcast_def_link); - fail_if(ret == 0, "unsupported PICO_IP_MULTICAST_IF succeeded\n"); - ret = pico_socket_getoption(s, PICO_IP_MULTICAST_IF, &mcast_def_link); - fail_if(ret == 0, "unsupported PICO_IP_MULTICAST_IF succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_TTL, &ttl); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_TTL failed\n"); - - ret = pico_socket_getoption(s, PICO_IP_MULTICAST_TTL, &getttl); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_TTL failed\n"); - fail_if(getttl != ttl, "setoption ttl != getoption ttl\n"); - - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_LOOP, &loop); - fail_if(ret == 0, "PICO_IP_MULTICAST_LOOP succeeded with invalid (not 0 or 1) loop value\n"); - loop = 0; - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_LOOP, &loop); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_LOOP failed disabling\n"); - ret = pico_socket_getoption(s, PICO_IP_MULTICAST_LOOP, &getloop); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_LOOP failed getting value\n"); - fail_if(getloop != loop, "setoption loop != getoption loop\n"); - _mreq.mcast_group_addr = inaddr_dst; - _mreq.mcast_link_addr = inaddr_link[0]; - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "supported PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "supported PICO_IP_DROP_MEMBERSHIP failed\n"); - _mreq.mcast_group_addr = inaddr_dst; - _mreq.mcast_link_addr = inaddr_null; - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed with valid NULL (use default) link address\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed with valid NULL (use default) link address\n"); - _mreq.mcast_group_addr = inaddr_uni; - _mreq.mcast_link_addr = inaddr_link[0]; - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded with invalid (unicast) group address\n"); - _mreq.mcast_group_addr = inaddr_null; - _mreq.mcast_link_addr = inaddr_link[0]; - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded with invalid (NULL) group address\n"); - _mreq.mcast_group_addr = inaddr_dst; - _mreq.mcast_link_addr = inaddr_uni; - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded with invalid link address\n"); - _mreq.mcast_group_addr = inaddr_incorrect; - _mreq.mcast_link_addr = inaddr_link[0]; - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (not added) group address\n"); - _mreq.mcast_group_addr = inaddr_uni; - _mreq.mcast_link_addr = inaddr_link[0]; - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (unicast) group address\n"); - _mreq.mcast_group_addr = inaddr_null; - _mreq.mcast_link_addr = inaddr_link[0]; - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (NULL) group address\n"); - _mreq.mcast_group_addr = inaddr_dst; - _mreq.mcast_link_addr = inaddr_uni; - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (unicast) link address\n"); - - /* flow validation tests */ - printf("IGMP SETOPTION FLOW VALIDATION TEST\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed with err %s\n", strerror(pico_err)); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_UNBLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* stress tests */ - printf("IGMP SETOPTION STRESS TEST\n"); - for (k = 0; k < 2; k++) { - /* ADD for even combinations of group and link, ADD_SOURCE for uneven */ - for (i = 0; i < 16; i++) { - if (i % 2) { - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[i]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - } - } else { - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - } - } - } - /* UNBLOCK and DROP for even combinations, DROP_SOURCE for uneven */ - for (i = 0; i < 16; i++) { - if (i % 2) { - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_UNBLOCK_SOURCE failed\n"); - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[i]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - } else { - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - } - } - } - /* everything should be cleanup up, next iteration will fail if not */ - } - /* filter validation tests */ - printf("IGMP SETOPTION FILTER VALIDATION TEST\n"); - /* INCLUDE + INCLUDE expected filter: source of 0 and 1*/ - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - i = 0; - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 2) - fail("MCASTFilter (INCLUDE + INCLUDE) too many elements\n"); - - source = index->keyValue; - if (source->ip4.addr == mreq_source[0].mcast_source_addr.ip4.addr) { /* OK */ - } - else if (source->ip4.addr == mreq_source[1].mcast_source_addr.ip4.addr) { /* OK */ - } - else { - fail("MCASTFilter (INCLUDE + INCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* INCLUDE + EXCLUDE expected filter: source of 2 */ - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[2]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - i = 0; - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 1) - fail("MCASTFilter (INCLUDE + EXCLUDE) too many elements\n"); - - source = index->keyValue; - if (source->ip4.addr == mreq_source[2].mcast_source_addr.ip4.addr) { /* OK */ - } - else { - fail("MCASTFilter (INCLUDE + EXCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* EXCLUDE + INCLUDE expected filter: source of 0 and 1 */ - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - i = 0; - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 2) - fail("MCASTFilter (EXCLUDE + INCLUDE) too many elements\n"); - - source = index->keyValue; - if (source->ip4.addr == mreq_source[0].mcast_source_addr.ip4.addr) { /* OK */ - } - else if (source->ip4.addr == mreq_source[1].mcast_source_addr.ip4.addr) { /* OK */ - } - else { - fail("MCASTFilter (EXCLUDE + INCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* EXCLUDE + EXCLUDE expected filter: source of 3 and 4 */ - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[5]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[6]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - i = 0; - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 2) - fail("MCASTFilter (EXCLUDE + EXCLUDE) too many elements\n"); - - source = index->keyValue; - if (source->ip4.addr == mreq_source[3].mcast_source_addr.ip4.addr) { /* OK */ - } - else if (source->ip4.addr == mreq_source[4].mcast_source_addr.ip4.addr) { /* OK */ - } - else { - fail("MCASTFilter (EXCLUDE + EXCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - - ret = pico_socket_close(s); - fail_if(ret < 0, "socket close failed: %s\n", strerror(pico_err)); - ret = pico_socket_close(s1); - fail_if(ret < 0, "socket close failed: %s\n", strerror(pico_err)); -} -END_TEST -#endif - -START_TEST (test_slaacv4) -{ - uint32_t tmp; - struct pico_device *dev; - struct mock_device *mock; - char ip_addr[20]; - uint8_t macaddr1[6] = { - 0xc3, 0, 0, 0xa, 0xc, 0xf - }; - - - - /* verify min boundary*/ - tmp = SLAACV4_CREATE_IPV4(0); - pico_ipv4_to_string(ip_addr, tmp); - printf("IP address generated by slaac: %s\n", ip_addr); - - fail_if(long_be(tmp) < (long_be(SLAACV4_NETWORK) | SLAACV4_MINRANGE)); - - /* verify max boundary*/ - tmp = SLAACV4_CREATE_IPV4(0x00FD); - fail_if(long_be(tmp) > (long_be(SLAACV4_NETWORK) | 0x0000FEFF)); - - /* verify case where dev->eth is NULL */ - dev = pico_null_create("dummy"); - tmp = pico_slaacv4_getip(dev, 0); - fail_if(long_be(tmp) != (long_be(SLAACV4_NETWORK) | SLAACV4_MINRANGE)); - /* verify nominal case; two runs of slaacv4_get_ip need to return same value */ - mock = pico_mock_create(macaddr1); - tmp = pico_slaacv4_getip(mock->dev, 0); - fail_if(tmp != pico_slaacv4_getip(mock->dev, 0)); - -} -END_TEST diff --git a/ext/picotcp/test/unit/unit_ipv6.c b/ext/picotcp/test/unit/unit_ipv6.c deleted file mode 100644 index 1d918f1..0000000 --- a/ext/picotcp/test/unit/unit_ipv6.c +++ /dev/null @@ -1,760 +0,0 @@ - -#ifdef PICO_SUPPORT_IPV6 -START_TEST (test_ipv6) -{ - char ipstr[40] = { - 0 - }; - char ipstr0[] = "2001:0db8:130f:0000:0000:09c0:876a:130b"; - char ipstr0_t[] = "2001:0db8:130f:0000:0000:09c0:876a:130b"; - char ipstr1[] = "2001:db8:130f:0000:0000:09c0:876a:130b"; - char ipstr1_t[] = "2001:0db8:130f:0000:0000:09c0:876a:130b"; - char ipstr2[] = "2001:b8:130f:0000:0000:09c0:876a:130b"; - char ipstr2_t[] = "2001:00b8:130f:0000:0000:09c0:876a:130b"; - char ipstr3[] = "2001:8:130f:0000:0000:09c0:876a:130b"; - char ipstr3_t[] = "2001:0008:130f:0000:0000:09c0:876a:130b"; - char ipstr4[] = "2001:8:130f:0:0:09c0:876a:130b"; - char ipstr4_t[] = "2001:0008:130f:0000:0000:09c0:876a:130b"; - char ipstr5[] = "2001::8:130f:09c0:876a:130b"; - char ipstr5_t[] = "2001:0000:0000:0008:130f:09c0:876a:130b"; - char ipstr6[] = "2001::8:09c0:876a:130b"; - char ipstr6_t[] = "2001:0000:0000:0000:0008:09c0:876a:130b"; - char ipstr7[] = "2001::8:876a:130b"; - char ipstr7_t[] = "2001:0000:0000:0000:0000:0008:876a:130b"; - char ipstr8[] = "2001::876a:130b"; - char ipstr8_t[] = "2001:0000:0000:0000:0000:0000:876a:130b"; - char ipstr9[] = "ff01::1"; - char ipstr9_t[] = "ff01:0000:0000:0000:0000:0000:0000:0001"; - char ipstr10[] = "::1"; - char ipstr10_t[] = "0000:0000:0000:0000:0000:0000:0000:0001"; - char ipstr11[] = "fe80::"; - char ipstr11_t[] = "fe80:0000:0000:0000:0000:0000:0000:0000"; - char ipstr12[] = "::"; - char ipstr12_t[] = "0000:0000:0000:0000:0000:0000:0000:0000"; - char ipstr13[] = "2001:8:130f::09c0::130b"; /* invalid */ - char ipstr14[] = "2001:8:xxxx::09c0:130b"; /* invalid */ - char ipstr15[] = "2001:8:$$$$::09c0:130b"; /* invalid */ - char ipstr16[] = "2001:8:!@#$::%^&*:()0b"; /* invalid */ - char ipstr17[] = "2001:1"; /* invalid */ - char ipstr18[] = "20010db8:130f:0000:0000:09c0:876a:130b"; /* invalid */ - char ipstr19[] = "20010db8130f0000000009c0876a130b"; /* invalid */ - char ipstr20[] = "2001;0db8;130f;0000;0000;09c0;876a;130b"; /* invalid */ - uint8_t iphex0[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x0d, 0xb8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex1[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x0d, 0xb8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex2[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0xb8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex3[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0x08, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex4[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0x08, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex5[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x13, 0x0f, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex6[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex7[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex8[PICO_SIZE_IP6] = { - 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x6a, 0x13, 0x0b - }; - uint8_t iphex9[PICO_SIZE_IP6] = { - 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - uint8_t iphex10[PICO_SIZE_IP6] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - }; - uint8_t iphex11[PICO_SIZE_IP6] = { - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - uint8_t iphex12[PICO_SIZE_IP6] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - struct pico_ip6 iphex_a = {{ 0x20, 0x01, 0x0d, 0xb8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; - struct pico_ip6 iphex_r = {{ 0x40, 0x02, 0x0d, 0xb8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}; - struct pico_ip6 iphex_gw = {{ 0x20, 0x01, 0x0d, 0xb8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f }}; - struct pico_ip6 nm64 = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; - struct pico_ip6 nm128 = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}; - struct pico_ip6 ipaddr = {{0}}; - - struct pico_ip6 _gw, r[IP_TST_SIZ], a[IP_TST_SIZ], gw[IP_TST_SIZ], *source[IP_TST_SIZ]; - struct pico_device *dev[IP_TST_SIZ]; - struct pico_ipv6_link *l[IP_TST_SIZ]; - struct pico_ipv6_link *_link = NULL; - struct pico_ipv6_route *_route = NULL; - char devname[8]; - int ret = 0; - int i = 0; - - pico_stack_init(); - - /* pico_string_to_ipv6 and pico_ipv6_to_string */ - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr0); - pico_string_to_ipv6(ipstr0, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex0, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr0_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr1); - pico_string_to_ipv6(ipstr1, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex1, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr1_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr2); - pico_string_to_ipv6(ipstr2, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex2, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr2_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr3); - pico_string_to_ipv6(ipstr3, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex3, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr3_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr4); - pico_string_to_ipv6(ipstr4, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex4, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr4_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr5); - pico_string_to_ipv6(ipstr5, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex5, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr5_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr6); - pico_string_to_ipv6(ipstr6, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex6, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr6_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr7); - pico_string_to_ipv6(ipstr7, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex7, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr7_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr8); - pico_string_to_ipv6(ipstr8, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex8, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr8_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr9); - pico_string_to_ipv6(ipstr9, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex9, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr9_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr10); - pico_string_to_ipv6(ipstr10, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex10, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr10_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr11); - pico_string_to_ipv6(ipstr11, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex11, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr11_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 valid conversion of %s\n", ipstr12); - pico_string_to_ipv6(ipstr12, ipaddr.addr); - fail_if(memcmp(ipaddr.addr, iphex12, PICO_SIZE_IP6), "Error string to ipv6"); - pico_ipv6_to_string(ipstr, ipaddr.addr); - printf("pico_ipv6_to_string valid conversion to %s\n", ipstr); - fail_if(strncmp(ipstr, ipstr12_t, 40) != 0, "Error ipv6 to string"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr13); - ret = pico_string_to_ipv6(ipstr13, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr14); - ret = pico_string_to_ipv6(ipstr14, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr15); - ret = pico_string_to_ipv6(ipstr15, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr16); - ret = pico_string_to_ipv6(ipstr16, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr17); - ret = pico_string_to_ipv6(ipstr17, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr18); - ret = pico_string_to_ipv6(ipstr18, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr19); - ret = pico_string_to_ipv6(ipstr19, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - printf("pico_string_to_ipv6 invalid conversion of %s\n", ipstr20); - ret = pico_string_to_ipv6(ipstr20, ipaddr.addr); - fail_if(ret == 0, "Error string to ipv6"); - - /*link_add*/ - for (i = 0; i < 10; ++i) { - snprintf(devname, 8, "nul%d", i); - dev[i] = pico_null_create(devname); - a[i] = iphex_a; - a[i].addr[4] = (uint8_t)(a[i].addr[4] + i); - fail_if(pico_ipv6_link_add(dev[i], a[i], nm64) == NULL, "Error adding link"); - } - /*link_find + link_get + route_add*/ - for (i = 0; i < 10; ++i) { - gw[i] = iphex_gw; - gw[i].addr[4] = (uint8_t)(gw[i].addr[4] + i); - fail_unless(pico_ipv6_link_find(&a[i]) == dev[i], "Error finding link"); - l[i] = pico_ipv6_link_get(&a[i]); - fail_if(l[i] == NULL, "Error getting link"); - r[i] = iphex_r; - r[i].addr[4] = (uint8_t)(r[i].addr[4] + i); - fail_if(pico_ipv6_route_add(r[i], nm128, a[i], 1, l[i]) != 0, "Error adding route"); - } - /*get_gateway*/ - for (i = 0; i < 10; i++) { - _gw = pico_ipv6_route_get_gateway(&r[i]); - fail_if(memcmp(_gw.addr, a[i].addr, PICO_SIZE_IP6) != 0, "Error get gateway: returned wrong route"); - source[i] = pico_ipv6_source_find(&r[i]); - fail_if(memcmp(source[i]->addr, a[i].addr, PICO_SIZE_IP6) != 0, "Error find source: returned wrong route"); - } - /*route_del + link_del*/ - for (i = 0; i < 10; i++) { - fail_if(pico_ipv6_route_del(r[i], nm128, a[i], 1, l[i]) != 0, "Error deleting route"); - fail_if(pico_ipv6_link_del(dev[i], a[i]) != 0, "Error deleting link"); - } - /* add 2 links to dev[0] */ - _link = pico_ipv6_link_add(dev[0], a[0], nm64); - fail_if (!_link, "Error adding link"); - _link = pico_ipv6_link_add(dev[0], a[1], nm64); - fail_if (!_link, "Error adding link"); - /* add 2 routes to each of the links */ - ret = pico_ipv6_route_add(r[0], nm128, a[0], 1, l[0]); - fail_if(ret != 0, "Error adding route"); - ret = pico_ipv6_route_add(r[1], nm128, a[0], 1, l[0]); - fail_if(ret != 0, "Error adding route"); - ret = pico_ipv6_route_add(r[2], nm128, a[1], 1, l[1]); - fail_if(ret != 0, "Error adding route"); - ret = pico_ipv6_route_add(r[3], nm128, a[1], 1, l[1]); - fail_if(ret != 0, "Error adding route"); - - /* add 2 links to dev[1] */ - _link = pico_ipv6_link_add(dev[1], a[8], nm64); - fail_if (!_link, "Error adding link"); - _link = pico_ipv6_link_add(dev[1], a[9], nm64); - fail_if (!_link, "Error adding link"); - /* add 2 routes to each of the links */ - ret = pico_ipv6_route_add(r[6], nm128, a[8], 1, l[8]); - fail_if(ret != 0, "Error adding route"); - ret = pico_ipv6_route_add(r[7], nm128, a[8], 1, l[8]); - fail_if(ret != 0, "Error adding route"); - ret = pico_ipv6_route_add(r[8], nm128, a[9], 1, l[9]); - fail_if(ret != 0, "Error adding route"); - ret = pico_ipv6_route_add(r[9], nm128, a[9], 1, l[9]); - fail_if(ret != 0, "Error adding route"); - - /* destroy device, should clean up all links and routes */ - pico_device_destroy(dev[0]); - _link = pico_ipv6_link_get(&a[0]); - fail_if(_link != NULL, "Error destroying device"); - _link = pico_ipv6_link_get(&a[1]); - fail_if(_link != NULL, "Error destroying device"); - _link = pico_ipv6_link_get(&a[8]); - fail_if(_link == NULL, "Error destroying device"); - _link = pico_ipv6_link_get(&a[9]); - fail_if(_link == NULL, "Error destroying device"); - - _route = pico_ipv6_route_find(&r[0]); - fail_if(_route != NULL, "Error destroying device"); - _route = pico_ipv6_route_find(&r[1]); - fail_if(_route != NULL, "Error destroying device"); - _route = pico_ipv6_route_find(&r[2]); - fail_if(_route != NULL, "Error destroying device"); - _route = pico_ipv6_route_find(&r[3]); - fail_if(_route != NULL, "Error destroying device"); - - _route = pico_ipv6_route_find(&r[6]); - fail_if(_route == NULL, "Error destroying device"); - _route = pico_ipv6_route_find(&r[7]); - fail_if(_route == NULL, "Error destroying device"); - _route = pico_ipv6_route_find(&r[8]); - fail_if(_route == NULL, "Error destroying device"); - _route = pico_ipv6_route_find(&r[9]); - fail_if(_route == NULL, "Error destroying device"); -} -END_TEST - -#ifdef PICO_SUPPORT_MCAST -START_TEST (test_mld_sockopts) -{ - int i = 0, j = 0, k = 0, ret = 0; - struct pico_socket *s, *s1 = NULL; - struct pico_device *dev = NULL; - union pico_address *source = NULL; - union pico_address inaddr_dst = { - 0 - }, inaddr_incorrect = { - 0 - }, inaddr_uni = { - 0 - }, inaddr_null = { - 0 - }; - struct pico_ip6 netmask = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; - - union pico_address inaddr_link[2] = {0}; - union pico_address inaddr_mcast[8] = {0}; - union pico_address inaddr_source[8] = {0}; - struct pico_ip_mreq _mreq = {0}, mreq[16] = {0}; - struct pico_ip_mreq_source mreq_source[128] = {0}; - struct pico_tree_node *index = NULL; - struct pico_ipv6_link *ret_link = NULL; - int ttl = 64; - int getttl = 0; - int loop = 9; - int getloop = 0; - struct pico_ip6 mcast_def_link = { - 0 - }; - - pico_stack_init(); - - printf("START MLD SOCKOPTS TEST\n"); - - pico_string_to_ipv6("ff00:0:0:0:0:0:e007:707", inaddr_dst.ip6.addr); - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:2", inaddr_uni.ip6.addr); - pico_string_to_ipv6("ff00:0:0:0:0:0:e008:808", inaddr_incorrect.ip6.addr); - pico_string_to_ipv6("::", inaddr_null.ip6.addr); - - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:0001", inaddr_link[0].ip6.addr); /* 0 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a32:0001", inaddr_link[1].ip6.addr); /* 1 */ - - pico_string_to_ipv6("ff00:0:0:0:0:0:e801:100", inaddr_mcast[0].ip6.addr); /* 0 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e802:201", inaddr_mcast[1].ip6.addr); /* 1 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e803:302", inaddr_mcast[2].ip6.addr); /* 2 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e803:403", inaddr_mcast[3].ip6.addr); /* 3 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e803:504", inaddr_mcast[4].ip6.addr); /* 4 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e803:605", inaddr_mcast[5].ip6.addr); /* 5 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e803:706", inaddr_mcast[6].ip6.addr); /* 6 */ - pico_string_to_ipv6("ff00:0:0:0:0:0:e803:807", inaddr_mcast[7].ip6.addr); /* 7 */ - - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:100", inaddr_source[0].ip6.addr); /* 0 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:101", inaddr_source[1].ip6.addr); /* 1 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:102", inaddr_source[2].ip6.addr); /* 2 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:103", inaddr_source[3].ip6.addr); /* 3 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:104", inaddr_source[4].ip6.addr); /* 4 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:105", inaddr_source[5].ip6.addr); /* 5 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:106", inaddr_source[6].ip6.addr); /* 6 */ - pico_string_to_ipv6("fe80:0:0:0:0:0:a28:107", inaddr_source[7].ip6.addr); /* 7 */ - - /* 00 01 02 03 04 05 06 07 | 10 11 12 13 14 15 16 17 */ - for (i = 0; i < 16; i++) { - mreq[i].mcast_link_addr = inaddr_link[i / 8]; - mreq[i].mcast_group_addr = inaddr_mcast[i % 8]; - } - /* 000 001 002 003 004 005 006 007 | 010 011 012 013 014 015 016 017 */ - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - /* printf(">>>>> mreq_source[%d]: link[%d] mcast[%d] source[%d]\n", (i*8)+j, i/8, i%8, j); */ - mreq_source[(i * 8) + j].mcast_link_addr = inaddr_link[i / 8]; - mreq_source[(i * 8) + j].mcast_group_addr = inaddr_mcast[i % 8]; - mreq_source[(i * 8) + j].mcast_source_addr = inaddr_source[j]; - } - } - dev = pico_null_create("dummy0"); - ret_link = pico_ipv6_link_add(dev, inaddr_link[0].ip6, netmask); - fail_if(ret_link == NULL, "link add failed"); - dev = pico_null_create("dummy1"); - ret_link = pico_ipv6_link_add(dev, inaddr_link[1].ip6, netmask); - fail_if(ret_link == NULL, "link add failed"); - - - s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, NULL); - fail_if(s == NULL, "UDP socket open failed"); - s1 = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, NULL); - fail_if(s1 == NULL, "UDP socket open failed"); - - - /* argument validation tests */ - printf("MLD SETOPTION ARGUMENT VALIDATION TEST\n"); - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_IF, &mcast_def_link); - fail_if(ret == 0, "unsupported PICO_IP_MULTICAST_IF succeeded\n"); - ret = pico_socket_getoption(s, PICO_IP_MULTICAST_IF, &mcast_def_link); - fail_if(ret == 0, "unsupported PICO_IP_MULTICAST_IF succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_TTL, &ttl); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_TTL failed\n"); - - ret = pico_socket_getoption(s, PICO_IP_MULTICAST_TTL, &getttl); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_TTL failed\n"); - fail_if(getttl != ttl, "setoption ttl != getoption ttl\n"); - - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_LOOP, &loop); - fail_if(ret == 0, "PICO_IP_MULTICAST_LOOP succeeded with invalid (not 0 or 1) loop value\n"); - loop = 0; - ret = pico_socket_setoption(s, PICO_IP_MULTICAST_LOOP, &loop); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_LOOP failed disabling\n"); - ret = pico_socket_getoption(s, PICO_IP_MULTICAST_LOOP, &getloop); - fail_if(ret < 0, "supported PICO_IP_MULTICAST_LOOP failed getting value\n"); - fail_if(getloop != loop, "setoption loop != getoption loop\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_dst.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_link[0].ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "supported PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "supported PICO_IP_DROP_MEMBERSHIP failed\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_dst.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_null.ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed with valid NULL (use default) link address\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed with valid NULL (use default) link address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_uni.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_link[0].ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded with invalid (unicast) group address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_null.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_link[0].ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded with invalid (NULL) group address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_dst.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_uni.ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded with invalid link address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_incorrect.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_link[0].ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (not added) group address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_uni.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_link[0].ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (unicast) group address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_null.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_link[0].ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (NULL) group address\n"); - memcpy(&_mreq.mcast_group_addr, &inaddr_dst.ip6, sizeof(struct pico_ip6)); - memcpy(&_mreq.mcast_link_addr, &inaddr_uni.ip6, sizeof(struct pico_ip6)); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &_mreq); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded with invalid (unicast) link address\n"); - /* flow validation tests */ - printf("MLD SETOPTION FLOW VALIDATION TEST\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed with err %s\n", strerror(pico_err)); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret == 0, "PICO_IP_DROP_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret == 0, "PICO_IP_ADD_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_UNBLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_BLOCK_SOURCE succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_UNBLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret == 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP succeeded\n"); - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - /* stress tests */ - - printf("MLD SETOPTION STRESS TEST\n"); - for (k = 0; k < 2; k++) { - /* ADD for even combinations of group and link, ADD_SOURCE for uneven */ - for (i = 0; i < 16; i++) { - if (i % 2) { - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[i]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - } - } else { - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - } - } - } - /* UNBLOCK and DROP for even combinations, DROP_SOURCE for uneven */ - for (i = 0; i < 16; i++) { - if (i % 2) { - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_UNBLOCK_SOURCE, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_UNBLOCK_SOURCE failed\n"); - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[i]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - } else { - for (j = 0; j < 8; j++) { - ret = pico_socket_setoption(s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source[(i * 8) + j]); - fail_if(ret < 0, "PICO_IP_DROP_SOURCE_MEMBERSHIP failed\n"); - } - } - } - /* everything should be cleanup up, next iteration will fail if not */ - } - /* filter validation tests */ - printf("MLD SETOPTION FILTER VALIDATION TEST\n"); - /* INCLUDE + INCLUDE expected filter: source of 0 and 1*/ - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - i = 0; - - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 2) - fail("MCASTFilter (INCLUDE + INCLUDE) too many elements\n"); - - source = index->keyValue; - if (memcmp(&source->ip6, &mreq_source[0].mcast_source_addr, sizeof(struct pico_ip6)) == 0) { /* OK */ - } - else if (memcmp(&source->ip6, &mreq_source[1].mcast_source_addr, sizeof(struct pico_ip6)) == 0) { /* OK */ - } - else { - fail("MCASTFilter (INCLUDE + INCLUDE) incorrect\n"); - } - } - - - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* INCLUDE + EXCLUDE expected filter: source of 2 */ - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[2]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - i = 0; - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 1) - fail("MCASTFilter (INCLUDE + EXCLUDE) too many elements\n"); - - source = index->keyValue; - if (memcmp(&source->ip6, &mreq_source[2].mcast_source_addr, sizeof(struct pico_ip6)) == 0) { /* OK */ - } - else { - fail("MCASTFilter (INCLUDE + EXCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* EXCLUDE + INCLUDE expected filter: source of 0 and 1 */ - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_ADD_SOURCE_MEMBERSHIP failed\n"); - i = 0; - - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 2) - fail("MCASTFilter (EXCLUDE + INCLUDE) too many elements\n"); - - source = index->keyValue; - if (memcmp(&source->ip6, &mreq_source[0].mcast_source_addr, sizeof(struct pico_ip6)) == 0) { /* OK */ - } - else if (memcmp(&source->ip6, &mreq_source[1].mcast_source_addr, sizeof(struct pico_ip6)) == 0) { /* OK */ - } - else { - fail("MCASTFilter (EXCLUDE + INCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - /* EXCLUDE + EXCLUDE expected filter: source of 3 and 4 */ - ret = pico_socket_setoption(s, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[0]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[1]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s, PICO_IP_BLOCK_SOURCE, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_ADD_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_ADD_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[3]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[4]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[5]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_BLOCK_SOURCE, &mreq_source[6]); - fail_if(ret < 0, "PICO_IP_BLOCK_SOURCE failed\n"); - i = 0; - pico_tree_foreach(index, &MCASTFilter) - { - if (++i > 2) - fail("MCASTFilter (EXCLUDE + EXCLUDE) too many elements\n"); - - source = index->keyValue; - if (memcmp(&source->ip6, &mreq_source[3].mcast_source_addr, sizeof(struct pico_ip6) == 0)) { /* OK */ - } - else if (memcmp(&source->ip6, &mreq_source[4].mcast_source_addr, sizeof(struct pico_ip6)) == 0) { /* OK */ - } - else { - fail("MCASTFilter (EXCLUDE + EXCLUDE) incorrect\n"); - } - } - ret = pico_socket_setoption(s, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - ret = pico_socket_setoption(s1, PICO_IP_DROP_MEMBERSHIP, &mreq[0]); - fail_if(ret < 0, "PICO_IP_DROP_MEMBERSHIP failed\n"); - - - ret = pico_socket_close(s); - fail_if(ret < 0, "socket close failed: %s\n", strerror(pico_err)); - ret = pico_socket_close(s1); - fail_if(ret < 0, "socket close failed: %s\n", strerror(pico_err)); -} -END_TEST -#endif - - -#endif diff --git a/ext/picotcp/test/unit/unit_mem_manager.c b/ext/picotcp/test/unit/unit_mem_manager.c deleted file mode 100644 index 309b633..0000000 --- a/ext/picotcp/test/unit/unit_mem_manager.c +++ /dev/null @@ -1,2158 +0,0 @@ -/* PicoTCP unit test platform */ -/* How does it works: - * 1. Define your unit test function as described in the check manual - * 2. Add your test to the suite in the pico_suite() function - */ - -#include "pico_mm.c" -#include "pico_tree.c" -#include - -volatile pico_err_t pico_err; - -START_TEST (test_compare_slab_keys) -{ - - uint32_t len1 = 1200; - uint32_t len2 = 1600; - uint32_t len3 = 1600; - uint32_t*lenptr1; - uint32_t*lenptr2; - uint32_t*lenptr3; - uint32_t**doublelenptr1; - uint32_t**doublelenptr2; - uint32_t**doublelenptr3; - struct pico_mem_block*block1; - struct pico_mem_block*block2; - struct pico_mem_block*block3; - struct pico_mem_slab_node*node1; - struct pico_mem_slab_node*node2; - struct pico_mem_slab_node*node3; - - /* Dependencies: none */ - printf("\n***************Running test_compare_slab_keys***************\n\n"); - /* Scenario's to test: */ - /* >Compare a large size with a small size */ - /* >Compare a small size with a large size */ - /* >Compare equal sizes */ - /* >Finally, compare with int pointers and with slab_nodes */ - - block1 = pico_zalloc(sizeof(struct pico_mem_block)); - block1->internals.heap_block.size = 1200; - block2 = pico_zalloc(sizeof(struct pico_mem_block)); - block2->internals.heap_block.size = 1600; - block3 = pico_zalloc(sizeof(struct pico_mem_block)); - block3->internals.heap_block.size = 1600; - node1 = pico_zalloc(sizeof(struct pico_mem_slab_node)); - node1->slab = block1; - node2 = pico_zalloc(sizeof(struct pico_mem_slab_node)); - node2->slab = block2; - node3 = pico_zalloc(sizeof(struct pico_mem_slab_node)); - node3->slab = block3; - - lenptr1 = &len1; - lenptr2 = &len2; - lenptr3 = &len3; - doublelenptr1 = &lenptr1; - doublelenptr2 = &lenptr2; - doublelenptr3 = &lenptr3; - - ck_assert(compare_slab_keys(&node1, &node2) > 0); - ck_assert(compare_slab_keys(&node2, &node3) == 0); - ck_assert(compare_slab_keys(&node2, &node1) < 0); - - ck_assert(compare_slab_keys(&doublelenptr1, &doublelenptr2) > 0); - ck_assert(compare_slab_keys(&doublelenptr2, &doublelenptr3) == 0); - ck_assert(compare_slab_keys(&doublelenptr2, &doublelenptr1) < 0); - - ck_assert(compare_slab_keys(&doublelenptr1, &node1) == 0); - ck_assert(compare_slab_keys(&node3, &doublelenptr1) < 0); - - pico_free(block1); - pico_free(block2); - pico_free(block3); - pico_free(node1); - pico_free(node2); - pico_free(node3); -} -END_TEST - -START_TEST (test_manager_extra_alloc) -{ - - uint8_t*byteptr; - uint8_t*byteptr1; - uint8_t*byteptr2; - struct pico_mem_block*block; - size_t sizeLeft; - size_t size = 50; - - uint8_t*data0; - uint8_t*data1; - uint8_t*data2; - uint8_t*data3; - - struct pico_mem_manager_extra*heap_page; - struct pico_mem_manager_extra*heap_page2; - - - /* Dependencies: */ - /* >pico_zalloc */ - printf("\n***************Running test_manager_extra_alloc***************\n\n"); - /* Scenario's to test: */ - /* Page with enough space in it passed, space should not be split up further */ - /* Page with not enough space in it passed, manager isn't allowed to alloc further space */ - /* Page with not enough space in it passed, manager is allowed to alloc further space */ - /* Page with enough space in it passed, space should be split up further */ - - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra); - - /* Housekeeping of extra manager page */ - heap_page = pico_zalloc(PICO_MEM_PAGE_SIZE); - heap_page->blocks = 2; - heap_page->timestamp = 12345; - - heap_page->next = NULL; - /* Housekeeping of manager page */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->manager_extra = heap_page; - manager->used_size = 2 * PICO_MEM_PAGE_SIZE; - manager->size = 10 * PICO_MEM_PAGE_SIZE; - manager->first_page = NULL; -/* - byteptr = (uint8_t*) (heap_page+1); - block = (pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = 100; - sizeLeft -= sizeof(pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - byteptr += sizeof(pico_mem_block); - byteptr += block->internals.heap_block.size; - */ - /* First block in extra manager page, unusable due to too small size */ - byteptr = (uint8_t*) (heap_page + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(size / 2); - sizeLeft -= sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - - /* Second block in extra manager page, free with more than enough size */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(100 - size / 2); - sizeLeft -= sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - byteptr1 = byteptr; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - - /* Third block in extra manager page, not free, takes up remainder of the space, minus the space of one extra block */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - /* Size of this block is thus that only one of the two testblocks will fit in the page */ - block->internals.heap_block.size = (uint32_t)(sizeLeft - 2 * sizeof(struct pico_mem_block) - size); - sizeLeft -= sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - byteptr2 = byteptr; - - /* Fourth block in extra manager page, free, large enough size */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - - /* Second block will be used */ - data0 = _pico_mem_manager_extra_alloc(heap_page, size); - /* Fourth block will be used */ - data1 = _pico_mem_manager_extra_alloc(heap_page, size); - /* Limit the space */ - manager->size = 2 * PICO_MEM_PAGE_SIZE; - /* No more space for another block, no more space for another page, function should return NULL */ - data2 = _pico_mem_manager_extra_alloc(heap_page, size); - ck_assert(data2 == NULL); - /* Allow more space */ - manager->size = 10 * PICO_MEM_PAGE_SIZE; - /* New page will be allocated, first block in it will be used, the space will be split up properly */ - data2 = _pico_mem_manager_extra_alloc(heap_page, size); - heap_page2 = manager->manager_extra; - ck_assert(heap_page2 != heap_page); - ck_assert(heap_page2->next == heap_page); - ck_assert(manager->used_size == 3 * PICO_MEM_PAGE_SIZE); - data3 = _pico_mem_manager_extra_alloc(heap_page2, size); - - /* Check the buildup of page 1 */ - ck_assert(heap_page->blocks == 4); - ck_assert(heap_page->timestamp == 0); - - block = (struct pico_mem_block*) byteptr1; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == 100 - size / 2); - ck_assert(data0 == (byteptr1 + sizeof(struct pico_mem_block))); - - block = (struct pico_mem_block*) byteptr2; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == size); - ck_assert(data1 == (byteptr2 + sizeof(struct pico_mem_block))); - - /* Check the buildup of page 2 */ - ck_assert(heap_page2->blocks == 2); - ck_assert(heap_page2->timestamp == 0); - - byteptr = (uint8_t*) (heap_page2 + 1); - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra); - block = (struct pico_mem_block*) byteptr; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == size); - ck_assert(data2 == (byteptr + sizeof(struct pico_mem_block))); - sizeLeft -= sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - - block = (struct pico_mem_block*) byteptr; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == size); - ck_assert(data3 == (byteptr + sizeof(struct pico_mem_block))); - sizeLeft -= sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - - block = (struct pico_mem_block*) byteptr; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block->internals.heap_block.size == sizeLeft - sizeof(struct pico_mem_block)); - - /* DEPENDENCY ON CLEANUP */ - pico_mem_deinit(); -} -END_TEST - -START_TEST (test_page0_zalloc) -{ - uint8_t*byteptr; - struct pico_mem_block*block; - size_t size1 = 50; - uint8_t*temp; - size_t sizeLeft; - struct pico_mem_manager_extra*heap_page; - - /* Dependencies: */ - /* >pico_zalloc */ - /* >_pico_mem_manager_extra_alloc() */ - printf("\n***************Running test_page0_zalloc***************\n\n"); - - /* Scenario's to test: */ - /* Empty block somewhere that doesn't fit the needed space */ - /* Empty block somewhere that exactly fits the needed space */ - /* NOTE: Splitting up isn't implemented, assessed as not necessary */ - /* Large empty block in the middle of the heap */ - /* Empty space at the end that needs splitting up */ - - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager); - - /* Memory manager housekeeping */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - byteptr = (uint8_t*) (manager + 1); - /* Block 1: not free, size1 */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)size1; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Block 2: free, size1/2 */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(size1 / 2); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Block 3: free, size1 */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)size1; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Block 4: free, size1*2 */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(size1 * 2); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Rest of the heap space (free) */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - - pico_mem_page0_zalloc(size1); - pico_mem_page0_zalloc(size1); - pico_mem_page0_zalloc((size_t)size1); - sizeLeft -= sizeof(struct pico_mem_block); - sizeLeft -= size1; - - /* Check buildup of heap space */ - byteptr = (uint8_t*) (manager + 1); - block = (struct pico_mem_block*) byteptr; - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_FREE); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block->internals.heap_block.size == sizeLeft - sizeof(struct pico_mem_block)); - - /* Now, fill up the rest of the space minus a few bytes, so that the space can't be split up further */ - /* pico_mem_page0_zalloc(sizeLeft - sizeof(struct pico_mem_block) - 3); */ - pico_mem_page0_zalloc(sizeLeft - sizeof(struct pico_mem_block) - 3); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == sizeLeft - sizeof(struct pico_mem_block)); - - pico_free(manager); - - /* Extra scenario's: */ - /* No more space left in the main heap, a second page doesn't exist yet */ - /* No more space left in the main heap, a second heap_page exists (space left doesn't matter, extra_alloc handles that) */ - - /* Manager housekeeping */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->manager_extra = NULL; - manager->used_size = PICO_MEM_PAGE_SIZE; - manager->size = 10 * PICO_MEM_PAGE_SIZE; - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager); - - /* Heap space full */ - byteptr = (uint8_t*) (manager + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - - /* Limit manager space */ - manager->size = PICO_MEM_PAGE_SIZE; - /* Try to alloc another block, no more space in manager heap, no more pages can be created: NULL should be returned */ - temp = pico_mem_page0_zalloc(size1); - ck_assert(temp == NULL); - /* Allow more space usage */ - manager->size = 10 * PICO_MEM_PAGE_SIZE; - /* Alloc 2 more blocks */ - pico_mem_page0_zalloc(size1); - pico_mem_page0_zalloc(size1); - - /* Check extra manager page housekeeping */ - ck_assert(manager->manager_extra != NULL); - heap_page = manager->manager_extra; - - ck_assert(heap_page->blocks == 2); - ck_assert(heap_page->next == NULL); - ck_assert(heap_page->timestamp == 0); - ck_assert(manager->used_size == 2 * PICO_MEM_PAGE_SIZE); - - /* Check extra manager page heap */ - block = (struct pico_mem_block*) (heap_page + 1); - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == size1); - byteptr = (uint8_t*) block; - byteptr += sizeof(struct pico_mem_block); - byteptr += size1; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.size == size1); - - pico_free(manager->manager_extra); - pico_free(manager); -} -END_TEST - -START_TEST (test_init_page) -{ - uint8_t*byteptr; - uint32_t*lenptr; - uint32_t**doublelenptr = &lenptr; - int vlag = 0; - int i; - struct pico_mem_block*intermediate_heap_block; - struct pico_mem_page*page0; - struct pico_mem_block*block; - struct pico_mem_page*page1; - struct pico_mem_page*page2; - struct pico_mem_block*slab; - struct pico_tree_node*tree_node; - struct pico_mem_slab_node*slab_node; - uint32_t slabsize1; - uint32_t slabsize2; - - /* Dependencies: */ - /* >picotree_findNode */ - /* >pico_mem_page0_zalloc */ - printf("\n***************Running test_init_page***************\n\n"); - - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->first_page = page0; - manager->size = 10 * PICO_MEM_PAGE_SIZE; - manager->used_size = 2 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - page0->next_page = NULL; - - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block); - - page1 = pico_zalloc(PICO_MEM_PAGE_SIZE); - page2 = pico_zalloc(PICO_MEM_PAGE_SIZE); - - slabsize1 = PICO_MEM_DEFAULT_SLAB_SIZE; - /* Slabsize 975 => 4 slab blocks fit in the page with 44 heap size */ - /* with a minimum heap size of 100, one slab block will be used as heapspace */ - slabsize2 = 975; - - _pico_mem_init_page(page1, slabsize1); - _pico_mem_init_page(page2, slabsize2); - - /* Check the housekeeping of page1 */ - ck_assert(page1->slab_size == slabsize1); - ck_assert(page1->slabs_max == (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + slabsize1)); - ck_assert(page1->slabs_free == page1->slabs_max); - ck_assert(page1->timestamp == 0); - ck_assert(page1->heap_max_size == (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - page1->slabs_max * (sizeof(struct pico_mem_block) + slabsize1))); - ck_assert(page1->heap_max_free_space == page1->heap_max_size); - - /* Check the housekeeping of page2 */ - ck_assert(page2->slab_size == slabsize2); - ck_assert(page2->slabs_max == (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + slabsize2)); - ck_assert(page2->slabs_free == page2->slabs_max); - ck_assert(page2->timestamp == 0); - ck_assert(page2->heap_max_size == (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - page2->slabs_max * (sizeof(struct pico_mem_block) + slabsize2))); - ck_assert(page2->heap_max_free_space == page2->heap_max_size); - - /* Check the housekeeping of the manager, and the page linked list */ - ck_assert(manager->first_page == page2); - ck_assert(page2->next_page == page1); - ck_assert(page1->next_page == page0); - ck_assert(page0->next_page == NULL); - - /* Check the slab_node double linked list for all slabs of page1 */ - byteptr = (uint8_t*) (page1 + 1); - byteptr += sizeof(struct pico_mem_block); - byteptr += page1->heap_max_size; - slab = (struct pico_mem_block*) byteptr; - - lenptr = &slabsize1; - tree_node = pico_tree_findNode(&manager->tree, &doublelenptr); - ck_assert(tree_node != NULL); - slab_node = tree_node->keyValue; - while(slab_node != NULL) - { - if(slab_node->slab == slab) - { - vlag = 1; - break; - } - - slab_node = slab_node->next; - } - ck_assert(vlag != 0); - vlag = 0; - for(i = 0; i < page1->slabs_max - 1; i++) - { - byteptr += sizeof(struct pico_mem_block); - byteptr += page1->slab_size; - slab = (struct pico_mem_block*) byteptr; - slab_node = tree_node->keyValue; - while(slab_node != NULL) - { - if(slab_node->slab == slab) - { - vlag = 1; - break; - } - - slab_node = slab_node->next; - } - ck_assert(vlag != 0); - vlag = 0; - } - /* Check the slab_node double linked list for all slabs of page2 */ - byteptr = (uint8_t*) (page2 + 1); - byteptr += sizeof(struct pico_mem_block); - byteptr += page2->heap_max_size; - slab = (struct pico_mem_block*) byteptr; - - lenptr = &slabsize2; - tree_node = pico_tree_findNode(&manager->tree, &doublelenptr); - ck_assert(tree_node != NULL); - slab_node = tree_node->keyValue; - while(slab_node != NULL) - { - if(slab_node->slab == slab) - { - vlag = 1; - break; - } - - slab_node = slab_node->next; - } - ck_assert(vlag != 0); - vlag = 0; - for(i = 0; i < page2->slabs_max - 1; i++) - { - byteptr += sizeof(struct pico_mem_block); - byteptr += page2->slab_size; - slab = (struct pico_mem_block*) byteptr; - slab_node = tree_node->keyValue; - while(slab_node != NULL) - { - if(slab_node->slab == slab) - { - vlag = 1; - break; - } - - slab_node = slab_node->next; - } - ck_assert(vlag != 0); - vlag = 0; - } - /* DEPENDENCY ON CLEANUP */ - pico_mem_deinit(); - - /* Extra scenario: Managerheap almost full (enough space for a slab_node, but not the necessary tree node), try to init a page */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->first_page = page0; - manager->size = 3 * PICO_MEM_PAGE_SIZE; - manager->used_size = 3 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - page0->next_page = NULL; - - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block) - (sizeof(struct pico_mem_block) + sizeof(struct pico_tree_node)) - (sizeof(struct pico_mem_block) + sizeof(struct pico_mem_slab_node)); - byteptr = (uint8_t*) (block + 1); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = sizeof(struct pico_mem_slab_node); - intermediate_heap_block = block; - byteptr = (uint8_t*) (block + 1); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = sizeof(struct pico_tree_node); - - page1 = pico_zalloc(PICO_MEM_PAGE_SIZE); - _pico_mem_init_page(page1, slabsize1); - - /* Check the housekeeping of page1 */ - ck_assert(page1->slab_size == slabsize1); - ck_assert(page1->slabs_max == 0); - ck_assert(page1->slabs_free == page1->slabs_max); - ck_assert(page1->timestamp == 0); - ck_assert(page1->heap_max_size == (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - 2 * (sizeof(struct pico_mem_block) + slabsize1))); - ck_assert(page1->heap_max_free_space == page1->heap_max_size); - ck_assert(page1->next_page == page0); - ck_assert(intermediate_heap_block->internals.heap_block.free == HEAP_BLOCK_FREE); - - /* Extra scenario: Managerheap almost full (enough space for a slab_node and a tree node), try to init a page */ - manager->first_page = page0; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - _pico_mem_init_page(page1, slabsize1); - - /* Check the housekeeping of page1 */ - ck_assert(page1->slab_size == slabsize1); - ck_assert(page1->slabs_max == 1); - ck_assert(page1->slabs_free == page1->slabs_max); - ck_assert(page1->timestamp == 0); - ck_assert(page1->heap_max_size == (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - 2 * (sizeof(struct pico_mem_block) + slabsize1))); - ck_assert(page1->heap_max_free_space == page1->heap_max_size); - ck_assert(page1->next_page == page0); - ck_assert(intermediate_heap_block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - - /* DEPENDENCY ON CLEANUP */ - pico_mem_deinit(); -} -END_TEST - -START_TEST (test_mem_init_whitebox) -{ - struct pico_mem_page*page; - int amountOfSlabs; - - /* Dependencies: */ - /* >pico_zalloc */ - /* >_pico_mem_init_page */ - /* >PICO_FREE */ - printf("\n***************Running test test_mem_init_whitebox***************\n\n"); - - /* No manager should be instantiated */ - ck_assert(manager == NULL); - - /* Init memory segment that is too small */ - pico_err = 0; - pico_mem_init(2); - ck_assert(pico_err == PICO_ERR_ENOMEM); - ck_assert(manager == NULL); - - /* Init 10 pages of memory */ - pico_err = 0; - pico_mem_init(10 * PICO_MEM_PAGE_SIZE); - ck_assert(pico_err == 0); - - ck_assert(manager != NULL); - ck_assert(manager->first_page != NULL); - ck_assert(manager->manager_extra == NULL); - ck_assert(manager->size == 10 * PICO_MEM_PAGE_SIZE); - ck_assert(manager->used_size == 2 * PICO_MEM_PAGE_SIZE); - - page = manager->first_page; - amountOfSlabs = (PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block)) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(page->heap_max_size == (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - ((size_t)amountOfSlabs) * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - ck_assert(page->heap_max_free_space == page->heap_max_size); - ck_assert(page->next_page == NULL); - ck_assert(page->slab_size == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(page->slabs_max == amountOfSlabs); - /* printf("free = %u ?= %u = max\n", page->slabs_free, page->slabs_max); */ - ck_assert(page->slabs_free == page->slabs_max); - - pico_mem_deinit(); -} -END_TEST - -START_TEST (test_free_and_merge_heap_block) -{ - - uint8_t*byteptr; - struct pico_mem_block*block; - uint16_t size = 50; - uint32_t sizeLeft; - struct pico_mem_block*block1; - struct pico_mem_block*block2; - struct pico_mem_block*block3; - struct pico_mem_block*block4; - struct pico_mem_page*page; - - /* Dependencies: none */ - printf("\n***************Running test_free_and_merge_heap_block***************\n\n"); - - /* Scenario's to test: Structure: |block1|block2|block3|block4|-------|slabs */ - /* free block1 (no merging) */ - /* free block2, check whitespace in block1 (merging before the block) */ - /* free block4, check whitespace after block3 (merging after the block) */ - /* free block3, check whitespace in block1 (merging before and after the block) */ - - - page = pico_zalloc(PICO_MEM_PAGE_SIZE); - page->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - 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) + PICO_MEM_DEFAULT_SLAB_SIZE))); - page->heap_max_free_space = page->heap_max_size; - sizeLeft = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Block 1: */ - byteptr = (uint8_t*) (page + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block1 = block; - /* Block 2: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block2 = block; - /* Block 3: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block3 = block; - /* Block 4: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block4 = block; - /* Free space: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - /* Slab block 1 housekeeping */ - block = (struct pico_mem_block*) byteptr; - block->type = SLAB_BLOCK_TYPE; - /* Rest: don't care */ - - /* Free Block1: */ - _pico_mem_free_and_merge_heap_block(page, block1); - ck_assert(block1->type == HEAP_BLOCK_TYPE); - ck_assert(block1->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block1->internals.heap_block.size == size); - - /* Free Block2: */ - _pico_mem_free_and_merge_heap_block(page, block2); - ck_assert(block1->type == HEAP_BLOCK_TYPE); - ck_assert(block1->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block1->internals.heap_block.size == sizeof(struct pico_mem_block) + (size_t)(2 * size)); - - /* Free Block4: */ - _pico_mem_free_and_merge_heap_block(page, block4); - ck_assert(block4->type == HEAP_BLOCK_TYPE); - ck_assert(block4->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block4->internals.heap_block.size == sizeof(struct pico_mem_block) + size + sizeLeft); - - /* Free Block3: */ - _pico_mem_free_and_merge_heap_block(page, block3); - ck_assert(block1->type == HEAP_BLOCK_TYPE); - ck_assert(block1->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block1->internals.heap_block.size == page->heap_max_size); - /* printf("page->heap_max_size=%u ?= block1.size=%u\n", page->heap_max_size, block1->internals.heap_block.size); */ - - pico_free(page); - - /* Additional scenario to test: |block1|block2|block3|slabs */ - page = pico_zalloc(PICO_MEM_PAGE_SIZE); - page->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - 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) + PICO_MEM_DEFAULT_SLAB_SIZE))); - page->heap_max_free_space = page->heap_max_size; - sizeLeft = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Block 1: */ - byteptr = (uint8_t*) (page + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block) - 2 * (sizeof(struct pico_mem_block) + size)); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block1 = block; - /* Block 2: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block2 = block; - /* Block 3: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block3 = block; - /* Slab block 1 housekeeping */ - block = (struct pico_mem_block*) byteptr; - block->type = SLAB_BLOCK_TYPE; - /* Rest: don't care */ - - /* Free block3 */ - _pico_mem_free_and_merge_heap_block(page, block3); - ck_assert(block3->type == HEAP_BLOCK_TYPE); - ck_assert(block3->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block3->internals.heap_block.size == size); - - /* Free block2 */ - _pico_mem_free_and_merge_heap_block(page, block2); - ck_assert(block2->type == HEAP_BLOCK_TYPE); - ck_assert(block2->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block2->internals.heap_block.size == size + sizeof(struct pico_mem_block) + size); - - /* Free block1 */ - _pico_mem_free_and_merge_heap_block(page, block1); - ck_assert(block1->type == HEAP_BLOCK_TYPE); - ck_assert(block1->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block1->internals.heap_block.size == page->heap_max_free_space); - - pico_free(page); -} -END_TEST - -START_TEST (test_determine_max_free_space) -{ - uint32_t temp; - uint8_t*byteptr; - struct pico_mem_block*block; - uint16_t size = 50; - uint32_t sizeLeft; - struct pico_mem_block*block1; - struct pico_mem_block*block2; - struct pico_mem_block*block3; - struct pico_mem_block*block4; - struct pico_mem_page*page; - - /* Dependencies: none */ - printf("\n***************Running test_determine_max_free_space***************\n\n"); - - /* Scenario's to test: Structure: |size 50 f|size 100 nf|size 25 f|size 75 nf|nf|slabs */ - /* block4 with size 100 becomes f, previous max free size 50 */ - - /* Page housekeeping */ - page = pico_zalloc(PICO_MEM_PAGE_SIZE); - page->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - 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) + PICO_MEM_DEFAULT_SLAB_SIZE))); - page->heap_max_free_space = size; - sizeLeft = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Block 1: */ - byteptr = (uint8_t*) (page + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block1 = block; - /* Block 2: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(2 * size); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block2 = block; - /* Block 3: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = size / 2; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block3 = block; - /* Block 4: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(3 * size / 2); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block4 = block; - /* Rest of the space */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - /* Slab block 1 housekeeping */ - block = (struct pico_mem_block*) byteptr; - block->type = SLAB_BLOCK_TYPE; - /* Rest: don't care */ - - ck_assert(page->heap_max_free_space == size); - _pico_mem_determine_max_free_space(page); - ck_assert(page->heap_max_free_space == 3 * size / 2); - - /* All blocks full: max_free_space = 0 */ - block1->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block2->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block3->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block4->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - temp = _pico_mem_determine_max_free_space(page); - ck_assert(temp == 0); - ck_assert(page->heap_max_free_space == 0); - - pico_free(page); -} -END_TEST - -START_TEST (test_free_slab_block) -{ - - struct pico_mem_page*page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - struct pico_mem_page*page1 = pico_zalloc(PICO_MEM_PAGE_SIZE); - struct pico_mem_slab_node*slab_node; - struct pico_mem_slab_node*original_slab_node; - struct pico_mem_block*block; - struct pico_mem_block*slab_block1; - struct pico_mem_block*original_slab_block; - struct pico_mem_block*slab_block2; - struct pico_tree_node*tree_node; - uint32_t size = 900; - uint32_t*lenptr; - uint32_t**doublelenptr; - uint8_t*byteptr; - - - /* Dependencies: */ - /* >pico_mem_page0_zalloc */ - /* >pico_tree_findNode */ - /* >pico_tree_insert */ - printf("\n***************Running test_free_slab_block***************\n\n"); - - /* Scenario's to test: */ - /* Freeing a block with an existing pico_tree_node */ - /* Freeing a block without an existing pico_tree_node */ - - /* Manager and page housekeepings */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - - - manager->first_page = page0; - manager->size = 10 * PICO_MEM_PAGE_SIZE; - manager->used_size = 3 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - page0->next_page = page1; - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - - page1->next_page = NULL; - page1->slab_size = size; - page1->slabs_max = 4; - page1->slabs_free = 0; - lenptr = &size; - doublelenptr = &lenptr; - - /* Manager heap space available */ - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block); - - /* Page 0: one slab free (slab_node exists in tree, for this size) */ - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->slabs_max = 2; - page0->slabs_free = 1; - original_slab_block = pico_zalloc(sizeof(struct pico_mem_block)); - original_slab_block->type = SLAB_BLOCK_TYPE; - original_slab_block->internals.slab_block.page = page0; - original_slab_node = pico_mem_page0_zalloc(sizeof(struct pico_mem_slab_node)); - original_slab_block->internals.slab_block.slab_node = original_slab_node; - original_slab_node->slab = original_slab_block; - original_slab_node->prev = NULL; - original_slab_node->next = NULL; - /* pico_tree_insert(&manager->tree, original_slab_node); */ - manager_tree_insert(&manager->tree, original_slab_node); - - /* Page 0: one slab not free */ - slab_block1 = pico_zalloc(sizeof(struct pico_mem_block)); - slab_block1->type = SLAB_BLOCK_TYPE; - slab_block1->internals.slab_block.page = page0; - slab_block1->internals.slab_block.slab_node = NULL; - - /* Page 1: all slabs not free, this one will be freed (no node in the tree for this size) */ - slab_block2 = pico_zalloc(sizeof(struct pico_mem_block)); - slab_block2->type = SLAB_BLOCK_TYPE; - slab_block2->internals.slab_block.page = page1; - slab_block2->internals.slab_block.slab_node = NULL; - - /* Free slabs, check page housekeepings */ - _pico_mem_free_slab_block(slab_block1); - _pico_mem_free_slab_block(slab_block2); - ck_assert(page0->slabs_free == page0->slabs_max); - ck_assert(page1->slabs_free == 1); - - /* Check the pico_tree, two nodes should exist, one with 2 slab_nodes, the other with 1 slab_node */ - tree_node = pico_tree_findNode(&manager->tree, original_slab_node); - ck_assert(tree_node != NULL); - ck_assert(tree_node->keyValue != NULL); - slab_node = (struct pico_mem_slab_node*) tree_node->keyValue; - ck_assert(slab_node->prev == NULL); - ck_assert(slab_node->next == original_slab_node); - ck_assert(slab_node->slab == slab_block1); - ck_assert(slab_node->next->prev == slab_node); - ck_assert(slab_node->next->next == NULL); - ck_assert(slab_node->next->slab == original_slab_block); - - tree_node = pico_tree_findNode(&manager->tree, &doublelenptr); - ck_assert(tree_node != NULL); - ck_assert(tree_node->keyValue != NULL); - slab_node = (struct pico_mem_slab_node*) tree_node->keyValue; - ck_assert(slab_node->prev == NULL); - ck_assert(slab_node->next == NULL); - ck_assert(slab_node->slab == slab_block2); - - pico_free(slab_block1); - pico_free(slab_block2); - pico_free(original_slab_block); - pico_mem_deinit(); - - /* Extra scenario: Managerheap almost full (enough space for a slab_node, but not the necessary tree node), try to free the slab block */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->first_page = page0; - manager->size = 2 * PICO_MEM_PAGE_SIZE; - manager->used_size = 2 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - page0->next_page = NULL; - - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block) - (sizeof(struct pico_mem_block) + sizeof(struct pico_mem_slab_node)); - byteptr = (uint8_t*) (block + 1); - byteptr += block->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = sizeof(struct pico_mem_slab_node); - - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->slabs_max = 2; - page0->slabs_free = 1; - slab_block1 = pico_zalloc(sizeof(struct pico_mem_block)); - slab_block1->type = SLAB_BLOCK_TYPE; - slab_block1->internals.slab_block.page = page0; - slab_block1->internals.slab_block.slab_node = NULL; - - _pico_mem_free_slab_block(slab_block1); - - /* Check the housekeeping of page0 */ - ck_assert(page0->slab_size == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(page0->slabs_max == 2); - ck_assert(page0->slabs_free == 2); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(manager->tree.root == &LEAF); - - /* Extra scenario: Managerheap full (not enough space for the slab_node), try to free the slab block */ - block->internals.heap_block.size = sizeof(struct pico_mem_slab_node) - 1; - page0->slabs_free = 1; - - _pico_mem_free_slab_block(slab_block1); - - /* Check the housekeeping of page0 */ - ck_assert(page0->slab_size == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(page0->slabs_max == 2); - ck_assert(page0->slabs_free == 2); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_FREE); - - pico_free(slab_block1); - /* DEPENDENCY ON CLEANUP */ - pico_mem_deinit(); -} -END_TEST - -START_TEST (test_zero_initialize) -{ - - size_t i; - size_t size = 100; - size_t leftBound = 5; - size_t rightBound = 5; - size_t uninitialized = 0; - size_t initialized = 0; - char*bytestream; - - /* Dependencies: none */ - printf("\n***************Running test_zero_initialize***************\n\n"); - - /* Scenario's to test: */ - /* >Zero-initializing a NULL pointer */ - /* >Zero-initializing a piece of memory like this: 11111|111111111111111111111|11111 => 11111|0000000000000000000000|11111 */ - - bytestream = pico_zalloc(size); - memset(bytestream, 'a', size); - - _pico_mem_zero_initialize(bytestream + leftBound, size - leftBound - rightBound); - for(i = 0; i < size; i++) - { - if(i < leftBound || i >= size - rightBound) - { - /* printf("Bytestream[%i] = '%c' ?= '%c'\n", i, bytestream[i], 'a'); */ - ck_assert(bytestream[i] == 'a'); - uninitialized++; - } - else - { - /* printf("Bytestream[%i] = '%c' ?= '%c'\n", i, bytestream[i], 0); */ - ck_assert(bytestream[i] == 0); - initialized++; - } - } - ck_assert(uninitialized == leftBound + rightBound); - ck_assert(initialized == size - leftBound - rightBound); - - pico_free(bytestream); -} -END_TEST - -START_TEST (test_find_heap_block) -{ - - uint8_t*byteptr; - struct pico_mem_block*block; - uint16_t size = 50; - uint32_t sizeLeft; - uint8_t*noData; - uint32_t block2Size; - uint8_t*startOfData2; - uint8_t*startOfData1; - struct pico_mem_block*block2; - struct pico_mem_block*block4; - struct pico_mem_page*page; - - /* Dependencies: */ - /* pico_mem_zero_initialize */ - /* pico_mem_determine_max_free_space */ - printf("\n***************Running test_find_heap_block***************\n\n"); - - /* Scenario's to test: Structure: [size 25 f| size 50 nf | size 60 f | size 50 nf | free space] */ - /* >Searching for a heap block of len > max_free_space */ - /* >Searching for a heap block of len < max_free_space, block cannot be split up in smaller blocks */ - /* >Searching for a heap block of len < max_free_space, block split up in smaller blocks */ - - /* Page housekeeping */ - page = pico_zalloc(PICO_MEM_PAGE_SIZE); - page->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - 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) + PICO_MEM_DEFAULT_SLAB_SIZE))); - page->heap_max_free_space = page->heap_max_size; - sizeLeft = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Block 0: */ - byteptr = (uint8_t*) (page + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = size / 2; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Block 1: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Block 2: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(size + size / 5); - block2Size = block->internals.heap_block.size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block2 = block; - /* Block 3: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - /* Free space: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - block4 = block; - /* Slab block 1 housekeeping */ - block = (struct pico_mem_block*) byteptr; - block->type = SLAB_BLOCK_TYPE; - /* Rest: don't care */ - - page->heap_max_free_space = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - noData = _pico_mem_find_heap_block(page, PICO_MEM_DEFAULT_SLAB_SIZE); - startOfData1 = _pico_mem_find_heap_block(page, size); - startOfData2 = _pico_mem_find_heap_block(page, size); - - ck_assert(noData == NULL); - - ck_assert(block2->type == HEAP_BLOCK_TYPE); - ck_assert(block2->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block2->internals.heap_block.size == block2Size); - ck_assert((uint8_t*) (block2 + 1) == startOfData1); - - ck_assert(block4->type == HEAP_BLOCK_TYPE); - ck_assert(block4->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - ck_assert(block4->internals.heap_block.size == size); - ck_assert((uint8_t*) (block4 + 1) == startOfData2); - - byteptr = (uint8_t*) (block4 + 1); - byteptr += block4->internals.heap_block.size; - sizeLeft -= block4->internals.heap_block.size; - block = (struct pico_mem_block*) byteptr; - ck_assert(block->type == HEAP_BLOCK_TYPE); - ck_assert(block->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block->internals.heap_block.size == sizeLeft - sizeof(struct pico_mem_block)); - - pico_free(page); -} -END_TEST - -START_TEST (test_find_slab) -{ - uint8_t*startOfData2; - uint8_t*noData; - uint32_t size = 900; - uint8_t*startOfData1; - struct pico_mem_block*slab_block1; - struct pico_mem_block*slab_block2; - struct pico_mem_page*page0; - struct pico_mem_block*block; - struct pico_mem_slab_node*slab_node1; - struct pico_mem_slab_node*slab_node2; - - /* Dependencies: */ - /* pico_tree_findNode */ - /* pico_tree_delete */ - /* pico_mem_zero_initialize */ - /* pico_mem_page0_free */ - printf("\n***************Running test_find_slab***************\n\n"); - - /* Scenario's to test */ - /* >The size you request has no slab_nodes available, it returns NULL */ - /* >The size you request has multiple slab nodes available, it returns one */ - /* >The size you request has one slab node available, it returns it and deletes the tree_node */ - - /* Manager housekeeping */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->first_page = page0; - manager->size = 10 * PICO_MEM_PAGE_SIZE; - manager->used_size = 2 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - - /* Manager heap: free */ - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block); - - /* Page 0 housekeeping */ - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->slabs_max = 2; - page0->slabs_free = 2; - page0->timestamp = 12345; - page0->next_page = NULL; - - /* Build tree with two slab nodes */ - slab_block1 = pico_zalloc(sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE); - slab_block1->type = SLAB_BLOCK_TYPE; - slab_block1->internals.slab_block.page = page0; - slab_node1 = pico_mem_page0_zalloc(sizeof(struct pico_mem_slab_node)); - slab_block1->internals.slab_block.slab_node = slab_node1; - slab_node1->slab = slab_block1; - slab_node1->prev = NULL; - /* pico_tree_insert(&manager->tree, slab_node1); */ - manager_tree_insert(&manager->tree, slab_node1); - - slab_block2 = pico_zalloc(sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE); - slab_block2->type = SLAB_BLOCK_TYPE; - slab_block2->internals.slab_block.page = page0; - slab_node2 = pico_mem_page0_zalloc(sizeof(struct pico_mem_slab_node)); - slab_node1->next = slab_node2; - slab_block2->internals.slab_block.slab_node = slab_node2; - slab_node2->slab = slab_block2; - slab_node2->prev = slab_node1; - slab_node2->next = NULL; - - /* Find slab with a size for which no tree_node exists */ - noData = _pico_mem_find_slab(size); - /* Find the existing slabs */ - startOfData1 = _pico_mem_find_slab(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(page0->slabs_free == 1); - ck_assert(page0->timestamp == 0); - startOfData2 = _pico_mem_find_slab(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(page0->slabs_free == 0); - - ck_assert(noData == NULL); - /* printf("startOfData1 = %p ?= %p\n", startOfData1, ((uint8_t*) (slab_block1)) + sizeof(pico_mem_block)); */ - ck_assert(startOfData1 == ((uint8_t*) (slab_block1)) + sizeof(struct pico_mem_block)); - /* printf("startOfData2 = %p ?= %p\n", startOfData2, ((uint8_t*) (slab_block2)) + sizeof(pico_mem_block)); */ - ck_assert(startOfData2 == ((uint8_t*) (slab_block2)) + sizeof(struct pico_mem_block)); - - /* printf("root=%p, LEAF=%p\n", manager->tree.root, &LEAF); */ - /* TODO: ????? */ - ck_assert(manager->tree.root == &LEAF); - - /* DEPENDENCY ON CLEANUP */ - pico_mem_deinit(); - pico_free(slab_block1); - pico_free(slab_block2); -} -END_TEST - -START_TEST (test_free) -{ - uint8_t*byteptr; - uint32_t sizeLeft2; - uint32_t sizeLeft1; - uint32_t size = 50; - struct pico_mem_block*block; - struct pico_mem_block*block1; - struct pico_mem_block*block2; - struct pico_mem_page*page1; - struct pico_mem_page*page0; - struct pico_mem_block*slab_block1; - - /* Dependencies */ - /* >_pico_mem_free_slab_block */ - /* >_pico_mem_free_and_merge_heap_block */ - /* >_pico_mem_determine_max_free_space */ - - printf("\n***************Running test_free***************\n\n"); - /* Scenario's: */ - /* Request to free a slab block: pico_mem_free_slab_block must be called => cover one case, if it works, then the forwarding has happened correctly */ - /* Request to free a heap block: correct page must be determined and the corresponding heap functions must be called => cover 2 cases in different pages to verify the page search */ - - /* Manager housekeeping */ - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - page1 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->first_page = page0; - manager->size = 10 * PICO_MEM_PAGE_SIZE; - manager->used_size = 3 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - - /* Manager heap: free */ - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block); - - /* Page 0 housekeeping */ - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->timestamp = 12345; - page0->next_page = page1; - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - page0->slabs_free = page0->slabs_max; - page0->heap_max_size = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - (page0->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - page0->heap_max_free_space = page0->heap_max_size; - sizeLeft1 = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page0->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Page 1 housekeeping */ - page1->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page1->timestamp = 12345; - page1->next_page = NULL; - page1->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page1->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - page1->heap_max_size = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - (page1->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - page1->heap_max_free_space = page1->heap_max_size; - sizeLeft2 = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page1->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Set up the slab block */ - slab_block1 = pico_zalloc(sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE); - slab_block1->type = SLAB_BLOCK_TYPE; - slab_block1->internals.slab_block.page = page0; - slab_block1->internals.slab_block.slab_node = NULL; - page0->slabs_free--; - /* - pico_mem_slab_node* slab_node1 = pico_mem_page0_zalloc(sizeof(pico_mem_slab_node)); - slab_block1->internals.slab_block.slab_node = slab_node1; - slab_node1->slab = slab_block1; - slab_node1->prev = NULL; - slab_node1->next = NULL; - pico_tree_insert(&manager->tree, slab_node1); - */ - - /* Set up the two heap blocks */ - /* Block 1: */ - byteptr = (uint8_t*) (page0 + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft1 -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft1 -= block->internals.heap_block.size; - block1 = block; - /* Free space: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft1 - sizeof(struct pico_mem_block)); - sizeLeft1 -= (uint32_t)sizeof(struct pico_mem_block); - byteptr += (uint32_t)sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - /* Block 2: */ - byteptr = (uint8_t*) (page1 + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft2 -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft2 -= block->internals.heap_block.size; - block2 = block; - /* Free space: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft2 - sizeof(struct pico_mem_block)); - sizeLeft2 -= (uint32_t)sizeof(struct pico_mem_block); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - - /* Free the slab block and check it */ - ck_assert(page0->slabs_free == page0->slabs_max - 1); - pico_mem_free(slab_block1 + 1); - ck_assert(page0->slabs_free == page0->slabs_max); - - /* Free heap block 1 and check it */ - pico_mem_free(block1 + 1); - ck_assert(block1->type == HEAP_BLOCK_TYPE); - ck_assert(block1->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block1->internals.heap_block.size != size); - ck_assert(block2->internals.heap_block.free == HEAP_BLOCK_NOT_FREE); - - /* Free heap block 2 and check it */ - pico_mem_free(block2 + 1); - ck_assert(block2->type == HEAP_BLOCK_TYPE); - ck_assert(block2->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(block2->internals.heap_block.size != size); - - /* DEPENDENCY ON CLEANUP */ - pico_mem_deinit(); - pico_free(slab_block1); -} -END_TEST - -START_TEST (test_determine_slab_size) -{ - uint32_t slab_size = 1000; - uint32_t slab_size2 = 1400; - size_t result; - - /* Dependencies: */ - /* >_pico_mem_reset_slab_statistics */ - printf("\n***************Running test_determine_slab_size***************\n\n"); - /* Scenario's to test: */ - /* 1: Asking for another slabsize 3 times => switch slab size */ - /* 2: Asking for a bigger slab size => return the bigger slab size, but don't switch the default yet */ - /* 3: After 3 times, switch the size again */ - - _pico_mem_reset_slab_statistics(); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == 1200); - ck_assert(slab_size_global == 1200); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == 1200); - ck_assert(slab_size_global == 1200); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == 1200); - ck_assert(slab_size_global == 1200); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == 1200); - ck_assert(slab_size_global == 1200); - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == 1200); - ck_assert(slab_size_global == 1200); - - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1200); - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1200); - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1200); - - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1400); - - result = _pico_mem_determine_slab_size(slab_size); - ck_assert(result == 1400); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == 1400); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == 1400); - - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - result = _pico_mem_determine_slab_size(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); - - result = _pico_mem_determine_slab_size(slab_size2); - ck_assert(result == PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(slab_size_global == PICO_MEM_DEFAULT_SLAB_SIZE); -} -END_TEST - -START_TEST (test_zalloc) -{ - - uint8_t*byteptr; - uint32_t oldHeapSize; - uint32_t sizeLeft1; - uint32_t size = 50; - uint32_t slabsize = 1200; - struct pico_mem_block*block; - struct pico_mem_block*slab_block; - struct pico_mem_page*page2; - struct pico_mem_page*page0; - struct pico_mem_page*page1; - struct pico_mem_slab_node*slab_node1; - - /* Dependencies: */ - /* >_pico_mem_determine_slab_size */ - /* >_pico_mem_find_slab */ - /* >_pico_zalloc */ - /* >_pico_mem_init_page */ - /* >_pico_mem_find_heap_block */ - printf("\n***************Running test_zalloc***************\n\n"); - /* Scenario's to test: */ - /* >0: Manager NULL or len>PICO_MAX_SLAB_SIZE */ - /* >1: Alloc for a slab: 1 exists */ - /* >2: Alloc for a slab: none exists but new page can be created */ - /* >3: Alloc for a slab: none exists and no new pages can be created */ - /* >4: Alloc for a heap block: 1 exists in a page somewhere */ - /* >5: Alloc for a heap block: none exists but new page can be created */ - /* >6: Alloc for a heap block: none exists and no new pages can be created, and a slab block is free (then we know the correct function is called, no need to test the case of a non-existing slab) */ - /* >7: Another default slabsize; a new page must be created with this size */ - /* >8: Request for a heap size of less than the minimum object size must still result in an allocation of the minimum object size */ - - - /* Scenario 0, part 1: manager = NULL */ - printf("SCENARIO 0\n"); - byteptr = pico_mem_zalloc(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(byteptr == NULL); - - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - page0 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->first_page = page0; - manager->size = 3 * PICO_MEM_PAGE_SIZE; - manager->used_size = 2 * PICO_MEM_PAGE_SIZE; - manager->tree.compare = compare_slab_keys; - manager->tree.root = &LEAF; - manager->manager_extra = NULL; - - - block = (struct pico_mem_block*) (manager + 1); - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_FREE; - block->internals.heap_block.size = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager) - sizeof(struct pico_mem_block); - - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->timestamp = 12345; - page0->next_page = NULL; - page0->slab_size = PICO_MEM_DEFAULT_SLAB_SIZE; - page0->slabs_max = ((PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - PICO_MIN_HEAP_SIZE) / (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE)); - page0->slabs_free = page0->slabs_max; - page0->heap_max_size = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - sizeof(struct pico_mem_block) - (page0->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - /* page0->heap_max_free_space = page0->heap_max_size; */ - page0->heap_max_free_space = 0; - sizeLeft1 = (uint32_t)(PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_page) - (page0->slabs_max * (sizeof(struct pico_mem_block) + PICO_MEM_DEFAULT_SLAB_SIZE))); - - /* Set up the blocks */ - /* Block 1: */ - byteptr = (uint8_t*) (page0 + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft1 -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft1 -= block->internals.heap_block.size; - /* Free space: */ - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft1 - sizeof(struct pico_mem_block)); - sizeLeft1 -= (uint32_t)sizeof(struct pico_mem_block); - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - /* Slab block 1: */ - slab_block = (struct pico_mem_block*) byteptr; - slab_block->type = SLAB_BLOCK_TYPE; - slab_block->internals.slab_block.page = page0; - slab_block->internals.slab_block.slab_node = NULL; - byteptr += sizeof(struct pico_mem_block); - byteptr += PICO_MEM_DEFAULT_SLAB_SIZE; - page0->slabs_free--; - /* Slab slab_block 2: */ - slab_block = (struct pico_mem_block*) byteptr; - /* TODO: INVALID WRITE HERE: */ - slab_block->type = SLAB_BLOCK_TYPE; - slab_block->internals.slab_block.page = page0; - slab_node1 = pico_mem_page0_zalloc(sizeof(struct pico_mem_slab_node)); - slab_node1->slab = slab_block; - slab_node1->next = NULL; - slab_node1->prev = NULL; - slab_block->internals.slab_block.slab_node = slab_node1; - /* DEPENDENCY */ - /* pico_tree_insert(&manager->tree, slab_node1); */ - manager_tree_insert(&manager->tree, slab_node1); - - /* Scenario 0, part 2: len>PICO_MAX_SLAB_SIZE */ - byteptr = pico_mem_zalloc(PICO_MAX_SLAB_SIZE + 1); - ck_assert(byteptr == NULL); - /* Scenario 1: Ask for an existing slab block */ - printf("SCENARIO 1\n"); - byteptr = pico_mem_zalloc(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(byteptr == (uint8_t*) (slab_block + 1)); - /* Scenario 2: Ask for another slab block; a new page can be created */ - printf("SCENARIO 2\n"); - byteptr = pico_mem_zalloc(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(manager->used_size == 3 * PICO_MEM_PAGE_SIZE); - page1 = manager->first_page; - ck_assert(page1->next_page == page0); - ck_assert((uint8_t*) page1 < byteptr); - ck_assert(byteptr < ((uint8_t*) page1) + PICO_MEM_PAGE_SIZE); - /* Setup for scenario 3: */ - pico_mem_zalloc(PICO_MEM_DEFAULT_SLAB_SIZE); - /* Scenario 3: Ask for another slab block: no new page can be created, NULL should be returned */ - printf("SCENARIO 3\n"); - byteptr = pico_mem_zalloc(PICO_MEM_DEFAULT_SLAB_SIZE); - ck_assert(byteptr == NULL); - ck_assert(manager->used_size == 3 * PICO_MEM_PAGE_SIZE); - /* Scenario 4: Ask for an existing heap block */ - printf("SCENARIO 4\n"); - byteptr = pico_mem_zalloc(page1->heap_max_free_space); - /* TODO: Why? */ - /* byteptr = pico_mem_zalloc(page1->heap_max_free_space%4); */ - ck_assert(page1->heap_max_free_space == 0); - ck_assert((uint8_t*) page1 < byteptr); - ck_assert(byteptr < ((uint8_t*) page1) + PICO_MEM_PAGE_SIZE); - /* Setup for scenario 5: */ - manager->size += PICO_MEM_PAGE_SIZE; - /* Scenario 5; Ask for a heap block: none are available but a new page can be created */ - printf("SCENARIO 5\n"); - byteptr = pico_mem_zalloc(page1->heap_max_size); - /* TODO: Why? */ - /* byteptr = pico_mem_zalloc(page1->heap_max_size%4); */ - ck_assert(manager->used_size == 4 * PICO_MEM_PAGE_SIZE); - page2 = manager->first_page; - ck_assert(page2->next_page == page1); - ck_assert(page2->heap_max_free_space == 0); - ck_assert((uint8_t*) page2 < byteptr); - ck_assert(byteptr < ((uint8_t*) page2) + PICO_MEM_PAGE_SIZE); - /* Scenario 6: Ask for a heap block: none are available and no new page can be created, but a slab block is available */ - printf("SCENARIO 6\n"); - byteptr = pico_mem_zalloc(page1->heap_max_size); - ck_assert((uint8_t*) page2 < byteptr); - ck_assert(byteptr < ((uint8_t*) page2) + PICO_MEM_PAGE_SIZE); - /* Scenario 7: A new page with a new slabsize must be created */ - printf("SCENARIO 7\n"); - manager->size += 3 * PICO_MEM_PAGE_SIZE; - byteptr = pico_mem_zalloc(slabsize); - block = (struct pico_mem_block*) (byteptr - sizeof(struct pico_mem_block)); - ck_assert(block->internals.slab_block.page->slab_size == PICO_MEM_DEFAULT_SLAB_SIZE); - byteptr = pico_mem_zalloc(slabsize); - block = (struct pico_mem_block*) (byteptr - sizeof(struct pico_mem_block)); - ck_assert(block->internals.slab_block.page->slab_size == PICO_MEM_DEFAULT_SLAB_SIZE); - byteptr = pico_mem_zalloc(slabsize); - block = (struct pico_mem_block*) (byteptr - sizeof(struct pico_mem_block)); - ck_assert(block->internals.slab_block.page->slab_size == PICO_MEM_DEFAULT_SLAB_SIZE); - /* At this point, a new page should be created with the correct size */ - byteptr = pico_mem_zalloc(slabsize); - block = (struct pico_mem_block*) (byteptr - sizeof(struct pico_mem_block)); - ck_assert(block->internals.slab_block.page->slab_size < PICO_MEM_DEFAULT_SLAB_SIZE); - /* Scenario 8: A request for a heap block of less than PICO_MEM_MINIMUM_OBJECT_SIZE will have its size enlargened */ - printf("SCENARIO 8\n"); - oldHeapSize = manager->first_page->heap_max_free_space; - byteptr = pico_mem_zalloc(1); - ck_assert(oldHeapSize == manager->first_page->heap_max_free_space + sizeof(struct pico_mem_block) + PICO_MEM_MINIMUM_OBJECT_SIZE); - - /* - //TODO: Testing of profiling - struct profiling_data profiling_struct; - pico_mem_profile_collect_data(&profiling_struct); - printf("Struct: \n\tfree_heap_space = %u\n\tfree_slab_space = %u\n\tused_heap_space = %u\n\tused_slab_space = %u\n", profiling_struct.free_heap_space, profiling_struct.free_slab_space, profiling_struct.used_heap_space, profiling_struct.used_slab_space); - pico_mem_profile_scan_data(); - */ - - pico_mem_deinit(); -} -END_TEST - -START_TEST (test_page0_free) -{ - - uint32_t sizeLeft; - uint8_t*byteptr; - struct pico_mem_block*block; - struct pico_mem_block*block1; - struct pico_mem_block*block2; - struct pico_mem_block*block3; - struct pico_mem_manager_extra*heap_page; - struct pico_mem_manager_extra*heap_page2; - uint32_t size = 50; - uint32_t blockAmount = 5; - uint32_t blockAmount2 = 8; - - /* Dependencies: none */ - printf("\n***************Running test_page0_free***************\n\n"); - /* Scenario's to test: */ - /* >1: Freeing a block in the manager heap */ - /* >2: Freeing a block in an extra manager page */ - - manager = pico_zalloc(PICO_MEM_PAGE_SIZE); - - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager); - byteptr = (uint8_t*) (manager + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block1 = block; - - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - - heap_page = pico_zalloc(PICO_MEM_PAGE_SIZE); - heap_page2 = pico_zalloc(PICO_MEM_PAGE_SIZE); - manager->manager_extra = heap_page; - heap_page->next = heap_page2; - heap_page->blocks = blockAmount; - heap_page2->blocks = blockAmount2; - heap_page2->next = NULL; - - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra); - byteptr = (uint8_t*) (heap_page + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block2 = block; - - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - - sizeLeft = PICO_MEM_PAGE_SIZE - sizeof(struct pico_mem_manager_extra); - byteptr = (uint8_t*) (heap_page2 + 1); - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = size; - byteptr += sizeof(struct pico_mem_block); - byteptr += block->internals.heap_block.size; - sizeLeft -= (uint32_t)sizeof(struct pico_mem_block); - sizeLeft -= block->internals.heap_block.size; - block3 = block; - - block = (struct pico_mem_block*) byteptr; - block->type = HEAP_BLOCK_TYPE; - block->internals.heap_block.free = HEAP_BLOCK_NOT_FREE; - block->internals.heap_block.size = (uint32_t)(sizeLeft - sizeof(struct pico_mem_block)); - - /* Scenario 1 */ - pico_mem_page0_free(block1 + 1); - ck_assert(block1->type == HEAP_BLOCK_TYPE); - ck_assert(block1->internals.heap_block.free == HEAP_BLOCK_FREE); - - /* Scenario 2: */ - pico_mem_page0_free(block2 + 1); - ck_assert(block2->type == HEAP_BLOCK_TYPE); - ck_assert(block2->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(heap_page->blocks == blockAmount - 1); - - pico_mem_page0_free(block3 + 1); - ck_assert(block3->type == HEAP_BLOCK_TYPE); - ck_assert(block3->internals.heap_block.free == HEAP_BLOCK_FREE); - ck_assert(heap_page2->blocks == blockAmount2 - 1); - - /* Cleanup */ - pico_free(manager); - pico_free(heap_page); - pico_free(heap_page2); -} -END_TEST - -START_TEST (test_cleanup) -{ - /* Dependencies: */ - /* >pico_tree_findNode */ - /* >pico_tree_delete */ - /* >pico_mem_page0_free */ - /* >PICO_FREE */ - uint32_t timestamp = 1; - struct pico_mem_page*page; - struct pico_mem_manager_extra*heap_page; - - printf("\n***************Running test_cleanup***************\n\n"); - - - timestamp = 1000; - /* Initialized manager has 1 completely empty page */ - pico_mem_init(21 * PICO_MEM_PAGE_SIZE); - /* Page 2: extra page with 1 slab occupied */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - page->slabs_free--; - /* Page 3: 1 extra page with some heap occupied */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - page->heap_max_free_space--; - /* Page 4: 1 extra page with old timestamp */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - page->timestamp = 500; - /* Page 5: 1 extra page with recent timestamp */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - page->timestamp = 950; - /* Page 6: 1 extra page with wrong timestamp */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - page->timestamp = 1500; - /* Page 7: 1 extra page with same timestamp */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, PICO_MEM_DEFAULT_SLAB_SIZE); - page->timestamp = 1000; - /* Page 8: 1 extra page with 1 slab occupied, slabsize 1200 */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, 1200); - page->slabs_free--; - /* Page 9: 1 extra empty page, slabsize 1200 */ - page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - _pico_mem_init_page(page, 1200); - /* 1 empty extra manager page */ - heap_page = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - manager->manager_extra = heap_page; - heap_page->blocks = 0; - heap_page->timestamp = 0; - /* 1 non-empty extra manager page */ - heap_page->next = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - heap_page = heap_page->next; - heap_page->blocks = 1; - heap_page->timestamp = 0; - /* 1 empty extra manager page with old timestamp */ - heap_page->next = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - heap_page = heap_page->next; - heap_page->blocks = 0; - heap_page->timestamp = 500; - /* 1 empty manager page with recent timestamp */ - heap_page->next = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - heap_page = heap_page->next; - heap_page->blocks = 0; - heap_page->timestamp = 950; - /* 1 empty manager page with wrong timestamp */ - heap_page->next = malloc(PICO_MEM_PAGE_SIZE); - manager->used_size += PICO_MEM_PAGE_SIZE; - heap_page = heap_page->next; - heap_page->blocks = 0; - heap_page->timestamp = 1500; - /* END OF MANAGER PAGES */ - heap_page->next = NULL; - - /* Run 1 cleanup */ - pico_mem_cleanup(timestamp); - /* Check all pages and manager pages */ - page = manager->first_page; - /* Page 9: empty with timestamp 0 */ - ck_assert(page->timestamp == timestamp); - page = page->next_page; - /* Page 8: not empty, 1 slab free, slabsize 1200 */ - ck_assert(page->timestamp == 0); - ck_assert(page->slab_size == 1200); - ck_assert(page->slabs_free == page->slabs_max - 1); - page = page->next_page; - /* Page 7: empty with same timestamp */ - ck_assert(page->timestamp == timestamp); - page = page->next_page; - /* Page 6: empty with wrong timestamp */ - ck_assert(page->timestamp == timestamp); - page = page->next_page; - /* Page 5: empty with recent timestamp */ - ck_assert(page->timestamp != timestamp); - page = page->next_page; - /* Page 4: empty with old timestamp: removed */ - /* Page 3: not empty with 1B less heap */ - ck_assert(page->timestamp == 0); - ck_assert(page->heap_max_free_space == page->heap_max_size - 1); - page = page->next_page; - /* Page 2: not empty with 1 slab occupied */ - ck_assert(page->timestamp == 0); - ck_assert(page->slabs_free == page->slabs_max - 1); - page = page->next_page; - /* Page 1: was empty with timestamp 0 */ - ck_assert(page->timestamp == timestamp); - ck_assert(page->next_page == NULL); - /* Check all manager pages */ - heap_page = manager->manager_extra; - /* Page 1: was empty with timestamp 0 */ - ck_assert(heap_page->timestamp == timestamp); - heap_page = heap_page->next; - /* Page 2: not empty with 1 block occupied */ - ck_assert(heap_page->blocks == 1); - ck_assert(heap_page->timestamp == 0); - heap_page = heap_page->next; - /* Page 3: empty with old timestamp: removed */ - /* Page 4: empty with recent timestamp */ - ck_assert(heap_page->timestamp != timestamp); - heap_page = heap_page->next; - /* Page 5: empty with wrong timestamp */ - ck_assert(heap_page->timestamp == timestamp); - ck_assert(heap_page->next == NULL); - - /* Advance timestamp, run another cleanup */ - timestamp += 500; - pico_mem_cleanup(timestamp); - /* Check all pages and manager pages */ - page = manager->first_page; - /* Page 9: empty with timestamp 0 */ - /* Page 8: not empty with 1 slab occupied, slabsize 1200 */ - ck_assert(page->timestamp == 0); - ck_assert(page->slab_size == 1200); - ck_assert(page->slabs_free == page->slabs_max - 1); - page = page->next_page; - /* Page 7: empty with same timestamp */ - /* Page 6: empty with wrong timestamp */ - /* Page 5: empty with recent timestamp */ - /* Page 4: empty with old timestamp: removed */ - /* Page 3: not empty with 1B less heap */ - ck_assert(page->timestamp == 0); - ck_assert(page->heap_max_free_space == page->heap_max_size - 1); - page = page->next_page; - /* Page 2: not empty with 1 slab occupied */ - ck_assert(page->timestamp == 0); - ck_assert(page->slabs_free == page->slabs_max - 1); - ck_assert(page->next_page == NULL); - /* Page 1: was empty with timestamp 0 */ - /* Check all manager pages */ - heap_page = manager->manager_extra; - /* Page 1: was empty with timestamp 0 */ - /* Page 2: not empty with 1 block occupied */ - ck_assert(heap_page->blocks == 1); - ck_assert(heap_page->timestamp == 0); - ck_assert(heap_page->next == NULL); - /* Page 3: empty with old timestamp: removed */ - /* Page 4: empty with recent timestamp */ - /* Page 5: empty with wrong timestamp */ - - /* Still in use: manager page + 1 extra manager page + 3 normal pages */ - ck_assert(manager->used_size == 5 * PICO_MEM_PAGE_SIZE); - - /* Free extra manager page */ - manager->manager_extra->blocks = 0; - - timestamp += 500; - pico_mem_cleanup(timestamp); - ck_assert(manager->used_size == 5 * PICO_MEM_PAGE_SIZE); - ck_assert(manager->manager_extra->timestamp == timestamp); - timestamp += 500; - pico_mem_cleanup(timestamp); - ck_assert(manager->used_size == 4 * PICO_MEM_PAGE_SIZE); - ck_assert(manager->manager_extra == NULL); - - /* Free normal pages */ - page = manager->first_page; - page->slabs_free = page->slabs_max; - page = page->next_page; - page->heap_max_free_space = page->heap_max_size; - page = page->next_page; - page->slabs_free = page->slabs_max; - - timestamp += 500; - pico_mem_cleanup(timestamp); - ck_assert(manager->used_size == 4 * PICO_MEM_PAGE_SIZE); - page = manager->first_page; - ck_assert(page->timestamp == timestamp); - page = page->next_page; - ck_assert(page->timestamp == timestamp); - page = page->next_page; - ck_assert(page->timestamp == timestamp); - - timestamp += 500; - pico_mem_cleanup(timestamp); - ck_assert(manager->used_size == PICO_MEM_PAGE_SIZE); - - pico_mem_deinit(); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *mm = tcase_create("Memory_Manager"); - - tcase_add_test(mm, test_compare_slab_keys); - tcase_add_test(mm, test_manager_extra_alloc); - tcase_add_test(mm, test_page0_zalloc); - tcase_add_test(mm, test_init_page); - tcase_add_test(mm, test_mem_init_whitebox ); - tcase_add_test(mm, test_free_and_merge_heap_block); - tcase_add_test(mm, test_determine_max_free_space); - tcase_add_test(mm, test_free_slab_block); - tcase_add_test(mm, test_zero_initialize); - tcase_add_test(mm, test_find_heap_block); - tcase_add_test(mm, test_find_slab); - tcase_add_test(mm, test_free); - tcase_add_test(mm, test_determine_slab_size); - tcase_add_test(mm, test_zalloc); - tcase_add_test(mm, test_page0_free); - tcase_add_test(mm, test_cleanup); - suite_add_tcase(s, mm); - - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/unit/unit_mocks.c b/ext/picotcp/test/unit/unit_mocks.c deleted file mode 100644 index 2f1381d..0000000 --- a/ext/picotcp/test/unit/unit_mocks.c +++ /dev/null @@ -1,71 +0,0 @@ -#define BUFLEN (576 + 14 + 20 + 8) - -int mock_print_protocol(uint8_t *buf); -int printbuf(uint8_t *buf, uint32_t len, const char *str, uint8_t printbufactive); -int tick_it(uint32_t nticks); - -int mock_print_protocol(uint8_t *buf) -{ - uint8_t pnr = buf[0x17]; /* protocol number */ - - printf("transport protocol: %s\n", - (pnr == PICO_PROTO_ICMP4 ? "icmp4" : - (pnr == PICO_PROTO_IGMP ? "igmp" : - (pnr == PICO_PROTO_TCP ? "tcp" : - (pnr == PICO_PROTO_UDP ? "udp" : - (pnr == PICO_PROTO_ICMP6 ? "icmp6" : - "unknown proto")))))); - return 0; -} - -int printbuf(uint8_t *buf, uint32_t len, const char *str, uint8_t printbufactive) -{ - uint8_t printMethod = 0; - uint32_t cntr = 0; - uint32_t cntr2 = 0; - if((printbufactive) && (printMethod == 0)) { - printf("\n%s:\n", str); - for(cntr = 0; cntr < len; cntr++) { - if((cntr % 8) == 0 && cntr != 0) - printf(" "); - - if((cntr % 16) == 0 && cntr != 0) - printf("\n"); - - if((cntr % 16) == 0) - printf("%03x0 ", cntr2++); - - printf("%02x ", buf[cntr]); - } - printf("\n"); - }else if((printbufactive) && (printMethod == 1)) { - printf("\n%s:\n", str); - printf("Buf = {"); - for(cntr = 0; cntr < len; cntr++) { - if(cntr != 0) - printf(","); - - if((cntr % 16 == 0) && (cntr != 0)) - printf("\n"); - - printf("0x%02x", buf[cntr]); - } - printf("}\n"); - } - - return 0; -} - -#define BUFLEN (576 + 14 + 20 + 8) -#define DHCP_MSG_TYPE_DISCOVER (1) -#define DHCP_MSG_TYPE_OFFER (2) -#define DHCP_MSG_TYPE_REQUEST (3) -#define DHCP_MSG_TYPE_ACK (4) -int tick_it(uint32_t nticks) -{ - uint32_t i = 0; - for (i = 0; i < nticks; i++) { - pico_stack_tick(); - } - return 0; -} diff --git a/ext/picotcp/test/unit/unit_rbtree.c b/ext/picotcp/test/unit/unit_rbtree.c deleted file mode 100644 index feb9eeb..0000000 --- a/ext/picotcp/test/unit/unit_rbtree.c +++ /dev/null @@ -1,93 +0,0 @@ -/* RB tree unit test */ -typedef struct -{ - int value; -}elem; - -int compare(void *a, void *b); - -int compare(void *a, void *b) -{ - return ((elem *)a)->value - ((elem *)b)->value; -} - -static PICO_TREE_DECLARE(test_tree, compare); -static PICO_TREE_DECLARE(test_tree2, compare); -#define RBTEST_SIZE 20000 - -START_TEST (test_rbtree2) -{ - struct pico_tree_node *s; - elem *e; - int i, last; - struct timeval start, end; - gettimeofday(&start, 0); - - srand48(RBTEST_SIZE); /* use test-size as salt */ - for (i = 0; i < (RBTEST_SIZE >> 1); i++) - { - e = malloc(sizeof(elem)); - e->value = (int)lrand48() % RBTEST_SIZE; - if (pico_tree_findKey(&test_tree2, e)) { - free(e); - } else { - pico_tree_insert(&test_tree2, e); - } - } - gettimeofday(&end, 0); - printf("Rbtree test 2 inserted %d entries in %d milliseconds\n", RBTEST_SIZE, - (int)((end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000)); - last = 0; - pico_tree_foreach(s, &test_tree2){ - fail_if (last > ((elem *)(s->keyValue))->value, "error"); - last = ((elem *)(s->keyValue))->value; - } - - gettimeofday(&end, 0); - printf("Rbtree test 2 duration with %d entries: %d milliseconds\n", RBTEST_SIZE, - (int)((end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000)); - printf("Test finished.\n"); -} -END_TEST - -START_TEST (test_rbtree) -{ - struct pico_tree_node *s, *tmp; - elem t, *e; - int i; - struct timeval start, end; - printf("Started test...\n"); - gettimeofday(&start, 0); - - for (i = 0; i < (RBTEST_SIZE >> 1); i++) { - e = malloc(sizeof(elem)); - e->value = i; - pico_tree_insert(&test_tree, e); - /* RB_INSERT(rbtree, &RBTREE, e); */ - e = malloc(sizeof(elem)); - e->value = (RBTEST_SIZE - 1) - i; - pico_tree_insert(&test_tree, e); - } - i = 0; - pico_tree_foreach(s, &test_tree){ - fail_if (i++ != ((elem *)(s->keyValue))->value, "error"); - } - t.value = RBTEST_SIZE >> 2; - - e = pico_tree_findKey(&test_tree, &t); - fail_if(!e, "Search failed..."); - fail_if(e->value != t.value, "Wrong element returned..."); - - pico_tree_foreach_reverse_safe(s, &test_tree, tmp){ - fail_if(!s, "Reverse safe returned null"); - e = (elem *)pico_tree_delete(&test_tree, s->keyValue); - free(e); - } - - fail_if(!pico_tree_empty(&test_tree), "Not empty"); - gettimeofday(&end, 0); - printf("Rbtree test duration with %d entries: %d milliseconds\n", RBTEST_SIZE, - (int)((end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000)); - printf("Test finished...\n"); -} -END_TEST diff --git a/ext/picotcp/test/unit/unit_socket.c b/ext/picotcp/test/unit/unit_socket.c deleted file mode 100644 index ca040bd..0000000 --- a/ext/picotcp/test/unit/unit_socket.c +++ /dev/null @@ -1,521 +0,0 @@ - -int pico_aodv_init(void) -{ - return 0; -} -START_TEST (test_socket) -{ - int ret = 0; - uint16_t port_be = 0, porta, proto, port_got; - char buf[] = "test"; - struct pico_socket *sk_tcp, *sk_udp, *s, *sl, *sa; - struct pico_device *dev; - struct pico_ip4 inaddr_dst, inaddr_link, inaddr_incorrect, inaddr_uni, inaddr_null, netmask, orig, inaddr_got; - - int getnodelay = -1; - int nodelay = -1; - int count = 0; - - uint32_t getsocket_buffer = 0; - uint32_t socket_buffer = 0; - - pico_stack_init(); - - printf("START SOCKET TEST\n"); - - pico_string_to_ipv4("224.7.7.7", &inaddr_dst.addr); - pico_string_to_ipv4("10.40.0.2", &inaddr_link.addr); - pico_string_to_ipv4("224.8.8.8", &inaddr_incorrect.addr); - pico_string_to_ipv4("0.0.0.0", &inaddr_null.addr); - pico_string_to_ipv4("10.40.0.3", &inaddr_uni.addr); - - dev = pico_null_create("dummy"); - netmask.addr = long_be(0xFFFF0000); - ret = pico_ipv4_link_add(dev, inaddr_link, netmask); - fail_if(ret < 0, "socket> error adding link"); - - - /* socket_open passing wrong parameters */ - s = pico_socket_open(PICO_PROTO_IPV4, 99, NULL); - fail_if(s != NULL, "Error got socket wrong parameters"); - - s = pico_socket_open(PICO_PROTO_IPV4, 0xFFFF, NULL); - fail_if(s != NULL, "Error got socket"); - - s = pico_socket_open(99, PICO_PROTO_UDP, NULL); - fail_if(s != NULL, "Error got socket"); - - s = pico_socket_open(0xFFFF, PICO_PROTO_UDP, NULL); - fail_if(s != NULL, "Error got socket"); - - - sk_tcp = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, NULL); - fail_if(sk_tcp == NULL, "socket> tcp socket open failed"); - - - port_be = short_be(5555); - /* socket_bind passing wrong parameters */ - ret = pico_socket_bind(NULL, &inaddr_link, &port_be); - fail_if(ret == 0, "socket> tcp socket bound wrong parameter"); - ret = pico_socket_bind(sk_tcp, NULL, &port_be); - fail_if(ret == 0, "socket> tcp socket bound wrong parameter"); - ret = pico_socket_bind(sk_tcp, &inaddr_link, NULL); - fail_if(ret == 0, "socket> tcp socket bound wrong parameter"); - /* socket_getname passing wrong parameters */ - ret = pico_socket_getname(NULL, &inaddr_link, &port_be, &proto); - fail_if(ret == 0, "socket> tcp socket getname with wrong parameter"); - ret = pico_socket_getname(sk_tcp, NULL, &port_be, &proto); - fail_if(ret == 0, "socket> tcp socket getname with wrong parameter"); - ret = pico_socket_getname(sk_tcp, &inaddr_link, NULL, &proto); - fail_if(ret == 0, "socket> tcp socket getname with wrong parameter"); - ret = pico_socket_getname(sk_tcp, &inaddr_link, &port_be, NULL); - fail_if(ret == 0, "socket> tcp socket getname with wrong parameter"); - /* socket_bind passing correct parameters */ - ret = pico_socket_bind(sk_tcp, &inaddr_link, &port_be); - fail_if(ret < 0, "socket> tcp socket bind failed"); - count = pico_count_sockets(PICO_PROTO_TCP); - printf("Count: %d\n", count); - fail_unless(count == 1); - count = pico_count_sockets(0); - printf("Count: %d\n", count); - fail_unless(count == 1); - - sk_udp = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, NULL); - fail_if(sk_udp == NULL, "socket> udp socket open failed"); - - port_be = short_be(5555); - ret = pico_socket_bind(sk_udp, &inaddr_link, &port_be); - fail_if(ret < 0, "socket> udp socket bind failed"); - - fail_if (pico_count_sockets(PICO_PROTO_UDP) != 1); - fail_if (pico_count_sockets(0) != 2); - - - ret = pico_socket_getname(sk_udp, &inaddr_got, &port_got, &proto); - fail_if(ret < 0, "socket> udp socket getname failed"); - fail_if(inaddr_got.addr != inaddr_link.addr, "Getname: Address is different"); - fail_if(port_be != port_got, "Getname: Port is different"); - fail_if(proto != PICO_PROTO_IPV4, "Getname: proto is wrong"); - - /* socket_close passing wrong parameter */ - ret = pico_socket_close(NULL); - fail_if(ret == 0, "Error socket close with wrong parameters"); - - - /* socket_connect passing wrong parameters */ - ret = pico_socket_connect(sk_udp, NULL, port_be); - fail_if(ret == 0, "Error socket connect with wrong parameters"); - ret = pico_socket_connect(NULL, &inaddr_dst, port_be); - fail_if(ret == 0, "Error socket connect with wrong parameters"); - - /* socket_connect passing correct parameters */ - ret = pico_socket_connect(sk_udp, &inaddr_dst, port_be); - fail_if(ret < 0, "Error socket connect"); - ret = pico_socket_connect(sk_tcp, &inaddr_dst, port_be); - fail_if(ret < 0, "Error socket connect"); - - - /* testing listening socket */ - sl = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, NULL); - fail_if(sl == NULL, "socket> tcp socket open failed"); - port_be = short_be(6666); - ret = pico_socket_bind(sl, &inaddr_link, &port_be); - fail_if(ret < 0, "socket> tcp socket bind failed"); - /* socket_listen passing wrong parameters */ - ret = pico_socket_listen(sl, 0); - fail_if(ret == 0, "Error socket tcp socket listen done, wrong parameter"); - ret = pico_socket_listen(NULL, 10); - fail_if(ret == 0, "Error socket tcp socket listen done, wrong parameter"); - /* socket_listen passing correct parameters */ - ret = pico_socket_listen(sl, 10); - fail_if(ret < 0, "socket> tcp socket listen failed: %s", strerror(pico_err)); - - /* socket_accept passing wrong parameters */ - sa = pico_socket_accept(sl, &orig, NULL); - fail_if(sa != NULL, "Error socket tcp socket accept wrong argument"); - sa = pico_socket_accept(sl, NULL, &porta); - fail_if(sa != NULL, "Error socket tcp socket accept wrong argument"); - /* socket_accept passing correct parameters */ - sa = pico_socket_accept(sl, &orig, &porta); - fail_if(sa == NULL && pico_err != PICO_ERR_EAGAIN, "socket> tcp socket accept failed: %s", strerror(pico_err)); - - ret = pico_socket_close(sl); - fail_if(ret < 0, "socket> tcp socket close failed: %s\n", strerror(pico_err)); - - - /* testing socket read/write */ - /* socket_write passing wrong parameters */ - ret = pico_socket_write(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket write succeeded, wrong argument\n"); - ret = pico_socket_write(sk_tcp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket write succeeded, wrong argument\n"); - ret = pico_socket_write(sk_tcp, (void *)buf, 0); - fail_if(ret > 0, "Error socket write succeeded, wrong argument\n"); - /* socket_write passing correct parameters */ - ret = pico_socket_write(sk_tcp, (void *)buf, sizeof(buf)); - fail_if(ret < 0, "socket> tcp socket write failed: %s\n", strerror(pico_err)); - /* socket_read passing wrong parameters */ - ret = pico_socket_read(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket read succeeded, wrong argument\n"); - ret = pico_socket_read(sk_tcp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket read succeeded, wrong argument\n"); - ret = pico_socket_read(sk_tcp, (void *)buf, 0); - fail_if(ret > 0, "Error socket read succeeded, wrong argument\n"); - /* socket_read passing correct parameters */ - ret = pico_socket_read(sk_tcp, (void *)buf, sizeof(buf)); - fail_if(ret < 0, "socket> tcp socket read failed, ret = %d: %s\n", ret, strerror(pico_err)); /* tcp_recv returns 0 when no frame !? */ - - - /* send/recv */ - /* socket_send passing wrong parameters */ - ret = pico_socket_send(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket send succeeded, wrong argument\n"); - ret = pico_socket_send(sk_tcp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket send succeeded, wrong argument\n"); - ret = pico_socket_send(sk_tcp, (void *)buf, 0); - fail_if(ret > 0, "Error socket send succeeded, wrong argument\n"); - /* socket_write passing correct parameters */ - ret = pico_socket_send(sk_tcp, (void *)buf, sizeof(buf)); - fail_if(ret <= 0, "socket> tcp socket send failed: %s\n", strerror(pico_err)); - /* socket_recv passing wrong parameters */ - ret = pico_socket_recv(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket recv succeeded, wrong argument\n"); - ret = pico_socket_recv(sk_tcp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket recv succeeded, wrong argument\n"); - ret = pico_socket_recv(sk_tcp, (void *)buf, 0); - fail_if(ret > 0, "Error socket recv succeeded, wrong argument\n"); - /* socket_recv passing correct parameters */ - ret = pico_socket_recv(sk_tcp, (void *)buf, sizeof(buf)); - fail_if(ret < 0, "socket> tcp socket recv failed, ret = %d: %s\n", ret, strerror(pico_err)); /* tcp_recv returns 0 when no frame !? */ - - - /* sendto/recvfrom */ - /* socket_sendto passing wrong parameters */ - ret = pico_socket_sendto(NULL, (void *)buf, sizeof(buf), &inaddr_dst, port_be); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_tcp, NULL, sizeof(buf), &inaddr_dst, port_be); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_tcp, (void *)buf, 0, &inaddr_dst, port_be); - fail_if(ret > 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_tcp, (void *)buf, sizeof(buf), NULL, port_be); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_tcp, (void *)buf, sizeof(buf), &inaddr_dst, 0xFFFF); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - /* socket_write passing correct parameters */ - ret = pico_socket_sendto(sk_tcp, (void *)buf, sizeof(buf), &inaddr_dst, short_be(5555)); - fail_if(ret <= 0, "socket> udp socket sendto failed, ret = %d: %s\n", ret, strerror(pico_err)); - /* socket_recvfrom passing wrong parameters */ - ret = pico_socket_recvfrom(NULL, (void *)buf, sizeof(buf), &orig, &porta); - fail_if(ret >= 0, "Error socket recvfrom succeeded, wrong argument\n"); - ret = pico_socket_recvfrom(sk_tcp, NULL, sizeof(buf), &orig, &porta); - fail_if(ret >= 0, "Error socket recvfrom succeeded, wrong argument\n"); - ret = pico_socket_recvfrom(sk_tcp, (void *)buf, 0, &orig, &porta); - fail_if(ret > 0, "Error socket recvfrom succeeded, wrong argument\n"); - ret = pico_socket_recvfrom(sk_tcp, (void *)buf, sizeof(buf), NULL, &porta); - fail_if(ret > 0, "Error socket recvfrom succeeded, wrong argument\n"); - ret = pico_socket_recvfrom(sk_tcp, (void *)buf, sizeof(buf), &orig, NULL); - fail_if(ret > 0, "Error socket recvfrom succeeded, wrong argument\n"); - /* socket_recvfrom passing correct parameters */ - ret = pico_socket_recvfrom(sk_tcp, (void *)buf, sizeof(buf), &orig, &porta); - fail_if(ret != 0, "socket> tcp socket recvfrom failed, ret = %d: %s\n", ret, strerror(pico_err)); /* tcp_recv returns -1 when no frame !? */ - - - /* testing socket read/write */ - /* socket_write passing wrong parameters */ - ret = pico_socket_write(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket write succeeded, wrong argument\n"); - ret = pico_socket_write(sk_udp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket write succeeded, wrong argument\n"); - ret = pico_socket_write(sk_udp, (void *)buf, 0); - fail_if(ret > 0, "Error socket write succeeded, wrong argument\n"); - /* socket_write passing correct parameters */ - ret = pico_socket_write(sk_udp, (void *)buf, sizeof(buf)); - fail_if(ret < 0, "socket> tcp socket write failed: %s\n", strerror(pico_err)); - /* socket_read passing wrong parameters */ - ret = pico_socket_read(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket read succeeded, wrong argument\n"); - ret = pico_socket_read(sk_udp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket read succeeded, wrong argument\n"); - ret = pico_socket_read(sk_udp, (void *)buf, 0); - fail_if(ret > 0, "Error socket read succeeded, wrong argument\n"); - ret = pico_socket_read(sk_udp, (void *)buf, 0xFFFF + 1); - fail_if(ret >= 0, "Error socket read succeeded while len was > 0xFFFF"); - /* socket_read passing correct parameters */ - ret = pico_socket_read(sk_udp, (void *)buf, sizeof(buf)); - fail_if(ret != 0, "socket> udp socket read failed, ret = %d: %s\n", ret, strerror(pico_err)); - - - /* send/recv */ - /* socket_send passing wrong parameters */ - ret = pico_socket_send(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket send succeeded, wrong argument\n"); - ret = pico_socket_send(sk_udp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket send succeeded, wrong argument\n"); - ret = pico_socket_send(sk_udp, (void *)buf, 0); - fail_if(ret > 0, "Error socket send succeeded, wrong argument\n"); - /* socket_write passing correct parameters */ - ret = pico_socket_send(sk_udp, (void *)buf, sizeof(buf)); - fail_if(ret <= 0, "socket> tcp socket send failed: %s\n", strerror(pico_err)); - /* socket_recv passing wrong parameters */ - ret = pico_socket_recv(NULL, (void *)buf, sizeof(buf)); - fail_if(ret == 0, "Error socket recv succeeded, wrong argument\n"); - ret = pico_socket_recv(sk_udp, NULL, sizeof(buf)); - fail_if(ret == 0, "Error socket recv succeeded, wrong argument\n"); - ret = pico_socket_recv(sk_udp, (void *)buf, 0); - fail_if(ret > 0, "Error socket recv succeeded, wrong argument\n"); - ret = pico_socket_recv(sk_udp, (void *)buf, 0xFFFF + 1); - fail_if(ret >= 0, "Error socket recv succeeded while len was > 0xFFFF"); - /* socket_recv passing correct parameters */ - ret = pico_socket_recv(sk_udp, (void *)buf, sizeof(buf)); - fail_if(ret != 0, "socket> udp socket recv failed, ret = %d: %s\n", ret, strerror(pico_err)); - - - /* sendto/recvfrom */ - /* socket_sendto passing wrong parameters */ - ret = pico_socket_sendto(NULL, (void *)buf, sizeof(buf), &inaddr_dst, port_be); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_udp, NULL, sizeof(buf), &inaddr_dst, port_be); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_udp, (void *)buf, 0, &inaddr_dst, port_be); - fail_if(ret > 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_udp, (void *)buf, sizeof(buf), NULL, port_be); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - ret = pico_socket_sendto(sk_udp, (void *)buf, sizeof(buf), &inaddr_dst, 0xFFFF); - fail_if(ret >= 0, "Error socket sendto succeeded, wrong argument\n"); - /* socket_write passing correct parameters */ - ret = pico_socket_sendto(sk_udp, (void *)buf, sizeof(buf), &inaddr_dst, short_be(5555)); - fail_if(ret <= 0, "socket> udp socket sendto failed, ret = %d: %s\n", ret, strerror(pico_err)); - /* socket_recvfrom passing wrong parameters */ - ret = pico_socket_recvfrom(NULL, (void *)buf, sizeof(buf), &orig, &porta); - fail_if(ret >= 0, "Error socket recvfrom succeeded, wrong argument\n"); - ret = pico_socket_recvfrom(sk_udp, NULL, sizeof(buf), &orig, &porta); - fail_if(ret >= 0, "Error socket recvfrom succeeded, wrong argument\n"); - ret = pico_socket_recvfrom(sk_udp, (void *)buf, 0xFFFF + 1, &orig, &porta); - fail_if(ret >= 0, "Error socket recvfrom succeeded while len was > 0xFFFF"); - /* socket_recvfrom passing correct parameters */ - ret = pico_socket_recvfrom(sk_udp, (void *)buf, 0, &orig, &porta); - fail_if(ret != 0, "socket> udp socket recvfrom failed, ret = %d: %s\n", ret, strerror(pico_err)); - ret = pico_socket_recvfrom(sk_udp, (void *)buf, sizeof(buf), &orig, &porta); - fail_if(ret != 0, "socket> udp socket recvfrom failed, ret = %d: %s\n", ret, strerror(pico_err)); - - /* temporary fix, until Nagle problems are analyzed and fixed */ - { - nodelay = 0; - ret = pico_socket_setoption(sk_tcp, PICO_TCP_NODELAY, &nodelay); - } - - /* setoption/getoption */ - ret = pico_socket_getoption(sk_tcp, PICO_TCP_NODELAY, &getnodelay); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_TCP_NODELAY failed (err = %s)\n", strerror(pico_err)); - fail_if(getnodelay != 0, "socket> socket_setoption: default PICO_TCP_NODELAY != 0 (nagle disabled by default)\n"); - - nodelay = 1; - ret = pico_socket_setoption(sk_tcp, PICO_TCP_NODELAY, &nodelay); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_TCP_NODELAY failed\n"); - ret = pico_socket_getoption(sk_tcp, PICO_TCP_NODELAY, &getnodelay); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_TCP_NODELAY failed\n"); - fail_if(getnodelay == 0, "socket> socket_setoption: PICO_TCP_NODELAY is off (expected: on!)\n"); - - nodelay = 0; - ret = pico_socket_setoption(sk_tcp, PICO_TCP_NODELAY, &nodelay); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_TCP_NODELAY failed\n"); - ret = pico_socket_getoption(sk_tcp, PICO_TCP_NODELAY, &getnodelay); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_TCP_NODELAY failed\n"); - fail_if(getnodelay != 0, "socket> socket_setoption: PICO_TCP_NODELAY is on (expected: off!)\n"); - - - /* Set/get recv buffer (TCP) */ - ret = pico_socket_getoption(sk_tcp, PICO_SOCKET_OPT_RCVBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - fail_if(getsocket_buffer != PICO_DEFAULT_SOCKETQ, - "socket> socket_setoption: default PICO_SOCKET_OPT_SNDBUF != DEFAULT\n"); - - socket_buffer = PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_tcp, PICO_SOCKET_OPT_RCVBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - ret = pico_socket_getoption(sk_tcp, PICO_SOCKET_OPT_RCVBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_RCVBUF is != than expected\n"); - - socket_buffer = 2 * PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_tcp, PICO_SOCKET_OPT_RCVBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - ret = pico_socket_getoption(sk_tcp, PICO_SOCKET_OPT_RCVBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_RCVBUF is != than expected\n"); - - /* Set/get send buffer (TCP) */ - ret = pico_socket_getoption(sk_tcp, PICO_SOCKET_OPT_SNDBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - fail_if(getsocket_buffer != PICO_DEFAULT_SOCKETQ, - "socket> socket_setoption: default PICO_SOCKET_OPT_SNDBUF != DEFAULT got: %d exp: %d\n", getsocket_buffer, PICO_DEFAULT_SOCKETQ); - - socket_buffer = PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_tcp, PICO_SOCKET_OPT_SNDBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - ret = pico_socket_getoption(sk_tcp, PICO_SOCKET_OPT_SNDBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_SNDBUF is != than expected\n"); - - socket_buffer = 2 * PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_tcp, PICO_SOCKET_OPT_SNDBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - ret = pico_socket_getoption(sk_tcp, PICO_SOCKET_OPT_SNDBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_SNDBUF is != than expected\n"); - - /* Set/get recv buffer (UDP) */ - ret = pico_socket_getoption(sk_udp, PICO_SOCKET_OPT_RCVBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - fail_if(getsocket_buffer != PICO_DEFAULT_SOCKETQ, - "socket> socket_setoption: default PICO_SOCKET_OPT_SNDBUF != DEFAULT\n"); - - socket_buffer = PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_udp, PICO_SOCKET_OPT_RCVBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - ret = pico_socket_getoption(sk_udp, PICO_SOCKET_OPT_RCVBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_RCVBUF is != than expected\n"); - - socket_buffer = 2 * PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_udp, PICO_SOCKET_OPT_RCVBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - ret = pico_socket_getoption(sk_udp, PICO_SOCKET_OPT_RCVBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_RCVBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_RCVBUF is != than expected\n"); - - /* Set/get send buffer (UDP) */ - ret = pico_socket_getoption(sk_udp, PICO_SOCKET_OPT_SNDBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - fail_if(getsocket_buffer != PICO_DEFAULT_SOCKETQ, - "socket> socket_setoption: default PICO_SOCKET_OPT_SNDBUF != DEFAULT\n"); - - socket_buffer = PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_udp, PICO_SOCKET_OPT_SNDBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - ret = pico_socket_getoption(sk_udp, PICO_SOCKET_OPT_SNDBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_SNDBUF is != than expected\n"); - - socket_buffer = 2 * PICO_DEFAULT_SOCKETQ; - ret = pico_socket_setoption(sk_udp, PICO_SOCKET_OPT_SNDBUF, &socket_buffer); - fail_if(ret < 0, "socket> socket_setoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - ret = pico_socket_getoption(sk_udp, PICO_SOCKET_OPT_SNDBUF, &getsocket_buffer); - fail_if(ret < 0, "socket> socket_getoption: supported PICO_SOCKET_OPT_SNDBUF failed\n"); - fail_if(getsocket_buffer != socket_buffer, "UDP socket> socket_setoption: PICO_SOCKET_OPT_SNDBUF is != than expected\n"); - - /* Close sockets, eventually. */ - ret = pico_socket_close(sk_tcp); - fail_if(ret < 0, "socket> tcp socket close failed: %s\n", strerror(pico_err)); - ret = pico_socket_close(sk_udp); - fail_if(ret < 0, "socket> udp socket close failed: %s\n", strerror(pico_err)); -} -END_TEST - -#ifdef PICO_SUPPORT_CRC_FAULTY_UNIT_TEST -START_TEST (test_crc_check) -{ - uint8_t buffer[64] = { - 0x45, 0x00, 0x00, 0x40, /* start of IP hdr */ - 0x91, 0xc3, 0x40, 0x00, - 0x40, 0x11, 0x24, 0xcf, /* last 2 bytes are CRC */ - 0xc0, 0xa8, 0x01, 0x66, - 0xc0, 0xa8, 0x01, 0x64, /* end of IP hdr */ - 0x15, 0xb3, 0x1F, 0x90, /* start of UDP/TCP hdr */ - 0x00, 0x2c, 0x27, 0x22, /* end of UDP hdr */ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, /* end of TCP hdr */ - 0x01, 0x23, 0x45, 0x67, /* start of data */ - 0x89, 0xab, 0xcd, 0xef, - 0xc0, 0xca, 0xc0, 0x1a - }; - struct pico_frame *f = NULL; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) buffer; - struct pico_udp_hdr *udp_hdr = NULL; - struct pico_tcp_hdr *tcp_hdr = NULL; - uint32_t *f_usage_count = NULL; - uint8_t *f_buffer = NULL; - int ret = -1; - - printf("START CRC TEST\n"); - pico_stack_init(); - - /* IPv4 CRC unit tests */ - /* Allocated memory will not be freed when pico_ipv4_crc_check fails */ - f = calloc(1, sizeof(struct pico_frame)); - f_usage_count = calloc(1, sizeof(uint32_t)); - f_buffer = calloc(1, sizeof(uint8_t)); - f->net_hdr = buffer; - f->net_len = PICO_SIZE_IP4HDR; - f->transport_hdr = buffer + PICO_SIZE_IP4HDR; - f->transport_len = sizeof(buffer) - PICO_SIZE_IP4HDR; - f->usage_count = f_usage_count; - f->buffer = f_buffer; - *(f->usage_count) = 512; - - hdr->crc = 0; - printf(">>>>>>>>>>>>>>>>>>>>> CRC VALUE = %X\n", pico_checksum(hdr, PICO_SIZE_IP4HDR)); - hdr->crc = short_be(0x24CF); /* Make check pass */ - ret = pico_ipv4_crc_check(f); - fail_if(ret == 0, "correct IPv4 checksum got rejected\n"); - hdr->crc = short_be(0x8899); /* Make check fail */ - ret = pico_ipv4_crc_check(f); - fail_if(ret == 1, "incorrect IPv4 checksum got accepted\n"); - - /* UDP CRC unit tests */ - /* Allocated memory will be freed when pico_transport_crc_check fails */ - f = calloc(1, sizeof(struct pico_frame)); - f_usage_count = calloc(1, sizeof(uint32_t)); - f_buffer = calloc(1, sizeof(uint8_t)); - f->net_hdr = buffer; - f->transport_hdr = buffer + PICO_SIZE_IP4HDR; - f->transport_len = sizeof(buffer) - PICO_SIZE_IP4HDR; - f->usage_count = f_usage_count; - f->buffer = f_buffer; - *(f->usage_count) = 1; - hdr->proto = 0x11; /* UDP */ - hdr->crc = short_be(0x24cf); /* Set IPv4 CRC correct */ - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - - /* udp_hdr->crc = 0; */ - /* printf(">>>>>>>>>>>>>>>>>>>>> UDP CRC VALUE = %X\n", pico_udp_checksum_ipv4(f)); */ - ret = pico_transport_crc_check(f); - fail_if(ret == 0, "correct UDP checksum got rejected\n"); - udp_hdr->crc = 0; - ret = pico_transport_crc_check(f); - fail_if(ret == 0, "UDP checksum of 0 did not get ignored\n"); - udp_hdr->crc = short_be(0x8899); /* Make check fail */ - ret = pico_transport_crc_check(f); - fail_if(ret == 1, "incorrect UDP checksum got accepted\n"); - - /* TCP CRC unit tests */ - /* Allocated memory will be freed when pico_transport_crc_check fails */ - f = calloc(1, sizeof(struct pico_frame)); - f_usage_count = calloc(1, sizeof(uint32_t)); - f_buffer = calloc(1, sizeof(uint8_t)); - f->net_hdr = buffer; - f->transport_hdr = buffer + PICO_SIZE_IP4HDR; - f->transport_len = sizeof(buffer) - PICO_SIZE_IP4HDR; - f->usage_count = f_usage_count; - f->buffer = f_buffer; - *(f->usage_count) = 1; - hdr->proto = 0x06; /* TCP */ - hdr->crc = short_be(0x24cf); /* Set IPv4 CRC correct */ - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - tcp_hdr->seq = long_be(0x002c2722); /* Set sequence number correct */ - - /* tcp_hdr = 0; */ - /* printf(">>>>>>>>>>>>>>>>>>>>> TCP CRC VALUE = %X\n", pico_tcp_checksum_ipv4(f)); */ - tcp_hdr->crc = short_be(0x0016); /* Set correct TCP CRC */ - ret = pico_transport_crc_check(f); - fail_if(ret == 0, "correct TCP checksum got rejected\n"); - tcp_hdr->crc = short_be(0x8899); /* Make check fail */ - ret = pico_transport_crc_check(f); - fail_if(ret == 1, "incorrect TCP checksum got accepted\n"); -} -END_TEST -#endif diff --git a/ext/picotcp/test/unit/unit_timer.c b/ext/picotcp/test/unit/unit_timer.c deleted file mode 100644 index e00c811..0000000 --- a/ext/picotcp/test/unit/unit_timer.c +++ /dev/null @@ -1,40 +0,0 @@ -#define EXISTING_TIMERS 7 - - -START_TEST (test_timers) -{ - uint32_t T[128]; - int i; - struct pico_timer_ref *tref; - pico_stack_init(); - for (i = 0; i < 128; i++) { - pico_time expire = (pico_time)(999999 + i); - void (*timer)(pico_time, void *) =(void (*)(pico_time, void *))0xff00 + i; - void *arg = ((void*)0xaa00 + i); - - T[i] = pico_timer_add(expire, timer, arg); - printf("New timer %u\n", T[i]); - } - for (i = 0; i < 128; i++) { - void (*timer)(pico_time, void *) =(void (*)(pico_time, void *))0xff00 + i; - void *arg = ((void*)0xaa00 + i); - - fail_if((uint32_t)(i + 1) > Timers->n); - tref = heap_get_element(Timers, (uint32_t)i + EXISTING_TIMERS); - fail_unless(tref->id == T[i]); - fail_unless(tref->tmr->timer == timer); - fail_unless(tref->tmr->arg == arg); - } - for (i = 127; i >= 0; i--) { - printf("Deleting timer %d \n", i ); - pico_timer_cancel(T[i]); - printf("Deleted timer %d \n", i ); - tref = heap_get_element(Timers, (uint32_t)i + EXISTING_TIMERS); - fail_unless(tref->tmr == NULL); - } - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); -} -END_TEST diff --git a/ext/picotcp/test/units.c b/ext/picotcp/test/units.c deleted file mode 100644 index b043b30..0000000 --- a/ext/picotcp/test/units.c +++ /dev/null @@ -1,233 +0,0 @@ -/* PicoTCP unit test platform */ -/* How does it works: - * 1. Define your unit test function as described in the check manual - * 2. Add your test to the suite in the pico_suite() function - */ - - -/* Inclusion of all the modules to test */ -/* This allow direct access to static functions, and also - * by compiling this, the namespace is checked for clashes in - * static symbols. - */ -#include "pico_device.c" -#include "pico_frame.c" -#include "pico_stack.c" -#include "pico_protocol.c" -#include "pico_802154.c" -#include "pico_6lowpan.c" -#include "pico_6lowpan_ll.c" -#include "pico_ipv4.c" -#include "pico_socket.c" -#include "pico_socket_multicast.c" -#include "pico_socket_tcp.c" -#include "pico_socket_udp.c" -#include "pico_dev_null.c" -#include "pico_dev_mock.c" -#include "pico_udp.c" -#include "pico_tcp.c" -#include "pico_arp.c" -#include "pico_icmp4.c" -#include "pico_dns_client.c" -#include "pico_dns_common.c" -#include "pico_dhcp_common.c" -#include "pico_dhcp_server.c" -#include "pico_dhcp_client.c" -#include "pico_nat.c" -#include "pico_ipfilter.c" -#include "pico_tree.c" -#include "pico_slaacv4.c" -#include "pico_hotplug_detection.c" -#ifdef PICO_SUPPORT_MCAST -#include "pico_mcast.c" -#include "pico_igmp.c" -#endif -#ifdef PICO_SUPPORT_IPV6 -#include "pico_ipv6.c" -#include "pico_ipv6_nd.c" -#include "pico_icmp6.c" -#ifdef PICO_SUPPORT_MCAST -#include "pico_mld.c" -#endif -#endif - - -/* Include Check. */ -#include - -/* Inclusion of unit submodules. - * Historically, this code has been part of - * the units.c file. - * Moved for readability of the units. - */ -#include "unit_mocks.c" -#include "unit_ipv4.c" -#include "unit_icmp4.c" -#include "unit_dhcp.c" -#include "unit_dns.c" -#include "unit_rbtree.c" -#include "unit_socket.c" -#include "unit_timer.c" -#include "unit_arp.c" -#include "unit_ipv6.c" - -Suite *pico_suite(void); - -START_TEST (test_frame) -{ - struct pico_frame *f1; - struct pico_frame *cpy; - struct pico_frame *deepcpy; - - f1 = pico_frame_alloc(200); - f1->payload = f1->buffer + 32; - f1->net_hdr = f1->buffer + 16; - cpy = pico_frame_copy(f1); - deepcpy = pico_frame_deepcopy(f1); - fail_unless(*f1->usage_count == 2); - fail_unless(*deepcpy->usage_count == 1); - pico_frame_discard(f1); - fail_unless(*cpy->usage_count == 1); - pico_frame_discard(cpy); - fail_unless(*deepcpy->usage_count == 1); - pico_frame_discard(deepcpy); -} -END_TEST - -START_TEST (test_tick) -{ - pico_tick = (uint64_t)-1; - fail_if(pico_tick != 0xFFFFFFFFFFFFFFFF, "Failed to assign (uint64_t)-1 to pico_tick\n"); -} -END_TEST - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *ipv4 = tcase_create("IPv4"); - TCase *icmp = tcase_create("ICMP4"); - TCase *dhcp = tcase_create("DHCP"); - TCase *dns = tcase_create("DNS"); - TCase *rb = tcase_create("RB TREE"); - TCase *rb2 = tcase_create("RB TREE 2"); - TCase *socket = tcase_create("SOCKET"); - TCase *nat = tcase_create("NAT"); - TCase *ipfilter = tcase_create("IPFILTER"); -#ifdef PICO_SUPPORT_CRC_FAULTY_UNIT_TEST - TCase *crc = tcase_create("CRC"); -#endif - -#ifdef PICO_SUPPORT_MCAST - TCase *igmp = tcase_create("IGMP"); -#endif -#ifdef PICO_SUPPORT_IPV6 - TCase *ipv6 = tcase_create("IPv6"); -#ifdef PICO_SUPPORT_MCAST - TCase *mld = tcase_create("MLD"); -#endif -#endif - - TCase *frame = tcase_create("FRAME"); - TCase *timers = tcase_create("TIMERS"); - TCase *slaacv4 = tcase_create("SLAACV4"); - TCase *tick = tcase_create("pico_tick"); - TCase *arp = tcase_create("ARP"); - tcase_add_test(ipv4, test_ipv4); - tcase_set_timeout(ipv4, 20); - suite_add_tcase(s, ipv4); - - tcase_add_test(icmp, test_icmp4_ping); - tcase_add_test(icmp, test_icmp4_incoming_ping); - tcase_add_test(icmp, test_icmp4_unreachable_send); - tcase_add_test(icmp, test_icmp4_unreachable_recv); - suite_add_tcase(s, icmp); - - /* XXX: rewrite test_dhcp_client due to architectural changes to support multiple devices */ - /* tcase_add_test(dhcp, test_dhcp_client); */ - tcase_add_test(dhcp, test_dhcp_client_api); - - tcase_add_test(dhcp, test_dhcp_server_ipinarp); - tcase_add_test(dhcp, test_dhcp_server_ipninarp); - tcase_add_test(dhcp, test_dhcp_server_api); - tcase_add_test(dhcp, test_dhcp); - suite_add_tcase(s, dhcp); - - tcase_add_test(dns, test_dns); - suite_add_tcase(s, dns); - - tcase_add_test(rb, test_rbtree); - tcase_set_timeout(rb, 120); - suite_add_tcase(s, rb); - - tcase_add_test(rb2, test_rbtree2); - tcase_set_timeout(rb2, 20); - suite_add_tcase(s, rb2); - - tcase_add_test(socket, test_socket); - suite_add_tcase(s, socket); - - tcase_add_test(nat, test_nat_enable_disable); - tcase_add_test(nat, test_nat_translation); - tcase_add_test(nat, test_nat_port_forwarding); - tcase_set_timeout(nat, 30); - suite_add_tcase(s, nat); - - tcase_add_test(ipfilter, test_ipfilter); - tcase_set_timeout(ipfilter, 10); - suite_add_tcase(s, ipfilter); - -#ifdef PICO_SUPPORT_CRC_FAULTY_UNIT_TEST - tcase_add_test(crc, test_crc_check); - suite_add_tcase(s, crc); -#endif - -#ifdef PICO_SUPPORT_MCAST - tcase_add_test(igmp, test_igmp_sockopts); - suite_add_tcase(s, igmp); -#endif - - tcase_add_test(frame, test_frame); - suite_add_tcase(s, frame); - - tcase_add_test(timers, test_timers); - suite_add_tcase(s, timers); - - tcase_add_test(slaacv4, test_slaacv4); - suite_add_tcase(s, slaacv4); - - tcase_add_test(tick, test_tick); - suite_add_tcase(s, tick); - -#ifdef PICO_SUPPORT_IPV6 - tcase_add_test(ipv6, test_ipv6); - suite_add_tcase(s, ipv6); -#ifdef PICO_SUPPORT_MCAST - tcase_add_test(mld, test_mld_sockopts); - suite_add_tcase(s, mld); -#endif -#endif - - tcase_add_test(arp, arp_update_max_arp_reqs_test); - tcase_add_test(arp, arp_compare_test); - tcase_add_test(arp, arp_lookup_test); - tcase_add_test(arp, arp_expire_test); - tcase_add_test(arp, arp_receive_test); - tcase_add_test(arp, arp_get_test); - tcase_add_test(arp, tc_pico_arp_queue); - suite_add_tcase(s, arp); - return s; -} - - - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/ext/picotcp/test/units.sh b/ext/picotcp/test/units.sh deleted file mode 100755 index 87fd02c..0000000 --- a/ext/picotcp/test/units.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -rm -f /tmp/pico-mem-report-* - -ASAN_OPTIONS="detect_leaks=0" ./build/test/units || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_fragments.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_pico_stack.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_802154.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_6lowpan.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_ethernet.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_pico_protocol.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_pico_frame.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_seq.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_tcp.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_dev_loop.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_dns_client.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_dns_common.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_sntp_client.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_ipv6_nd.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_mdns.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_dns_sd.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_ipfilter.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_queue.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_tftp.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_aodv.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_dev_ppp.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_mld.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_igmp.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_hotplug_detection.elf || exit 1 -ASAN_OPTIONS="detect_leaks=0" ./build/test/modunit_strings.elf || exit 1 - -MAXMEM=`cat /tmp/pico-mem-report-* | sort -r -n |head -1` -echo -echo -echo -echo "MAX memory used: $MAXMEM" -rm -f /tmp/pico-mem-report-* - -echo "SUCCESS!" && exit 0 diff --git a/ext/picotcp/test/vde_sock_start.sh b/ext/picotcp/test/vde_sock_start.sh deleted file mode 100755 index cf0100e..0000000 --- a/ext/picotcp/test/vde_sock_start.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -gksu "vdecmd -s /tmp/pico.mgmt shutdown" -gksu "vdecmd -s /tmp/pico1.mgmt shutdown" -gksu "vde_switch -t pic0 -s /tmp/pic0.ctl -m 777 -M /tmp/pico.mgmt -d -hub" -gksu "vde_switch -t pic1 -x -s /tmp/pic1.ctl -m 777 -M /tmp/pico1.mgmt -d -hub" - -# we prefer to use ip over ifconfig (which is obsolete), but the script has to work when ip is not available as well -USINGIP=1 -command -v ip >/dev/null 2>&1 || USINGIP=0 - -if [ $USINGIP -eq 1 ]; -then - gksu "ip addr add 10.40.0.1/24 dev pic0" - gksu "ip addr add 10.50.0.1/24 dev pic1" -else - gksu "ifconfig pic0 10.40.0.1 netmask 255.255.255.0" - gksu "ifconfig pic1 10.50.0.1 netmask 255.255.255.0" -fi -#ping 10.40.0.3 & - - diff --git a/ext/picotcp/test/vde_sock_start_user.sh b/ext/picotcp/test/vde_sock_start_user.sh deleted file mode 100755 index 624cfc9..0000000 --- a/ext/picotcp/test/vde_sock_start_user.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -function help(){ - echo 'Cmd line arguments can be:' - echo 'start: to start the vde setup for the autotest.' - echo 'stop: to cleanup the vde setup for the autotest.' - exit -} - -function start_vde(){ - vde_switch -s /tmp/pic0.ctl -m 777 -M /tmp/pico.mgmt -d -hub - vde_switch -s /tmp/pic1.ctl -m 777 -M /tmp/pici.mgmt -d -hub -} - -start_vde - 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